2009-10-30 10 views
0

J'essaie de localiser des fichiers portant le même nom et de supprimer toutes les copies de plus petite taille, ne laissant que le plus grand. Par exemple: test.jpg = 2kb, test.jpg = 9kb, test.jpg = 5kb. Les fichiers 2kb et 5kb seraient supprimés, laissant seulement le 9kb. J'ai essayé quelques programmes de GUI pour faire ceci et ils ne m'ont pas aidé, puisque vous avez dû tout supprimer manuellement après avoir trouvé les copies (pas si bien quand il y a environ 400000 dupes!) Y at-il un script là-bas qui peut Est-ce que tout le monde le sait?Suppression de dupes de fichiers de plus petite taille

Répondre

0

Ce script Perl trouve tous les fichiers commençant dans le répertoire en cours. Il les place ensuite dans un hachage où le nom de base du fichier est la clé et la valeur est une paire (taille, chemin complet). Il itère ensuite sur les noms de base, trie les doublons et supprime tout sauf le plus grand.

Le fichier/bin/rm actuel est mis en commentaire. Assurez-vous que cela fait ce que vous voulez avant de le faire pour de vrai.

Véritable hackers perl: si je fais quelque chose de naïf/stupide ici, j'aimerais en savoir plus.

#!/usr/bin/perl -w 
use File::Basename; 
use strict; 

my @files = `/usr/bin/find -type f`; 
my %stats; 

# each hash key is the simple basename of the files 
# each hash value is a 2 element array of (size, fullpath) 
foreach my $file (@files) 
{ 
    chomp($file); 
    my $result = `/bin/ls -s $file`; 
    chomp($result); 
    if($result =~ /^(\d+)\s+(.*)/) 
    { 
     my ($basefile, $dir, $suffix) = fileparse($file); 
     push(@{$stats{$basefile}}, [$1, $2]); 
    } 
    else 
    { 
     printf STDERR "Unexpected ls output: $result\n"; 
    } 
} 

foreach my $file (keys %stats) 
{ 
    # sort from smallest to largest 
    my @sorted = sort {$b->[0] <=> $a->[0]} @{$stats{$file}}; 

    # remove the biggest one 
    pop(@sorted); 

    # for each one that's left remove it (use at your own risk!) 
    foreach my $path (@sorted) 
    { 
     # system("/bin/rm $path"); 
     printf "/bin/rm $path->[1]\n"; 
    } 
} 
1

Ceci trouve tous les fichiers et imprime leurs noms, tailles et nom-avec-chemin. Ensuite, il les trie par nom, puis par taille (décroissant) puis chemin. Le script awk passe par tous, mais le premier (le plus grand) et xargs les remet hors de echo (enlever le echo faire rm action prendre). Cela devrait fonctionner sur les fichiers avec des espaces dans leurs noms, mais pas sur ceux qui ont des nouvelles lignes ou des onglets dans leurs noms.

find -type f -printf "%f\t%s\t%p\n" | 
    sort -t $'\t' -k 1,1 -k 2,2rn -k 3,3 | 
    awk -F'\t' '{if ($1 == prevfile) printf "%s\0", $3; prevfile = $1}' | 
    xargs -0 -I{} echo rm \{\} 

Dans cette structure de répertoire (produit par tree -s), tous les fichiers nommés « fichier » serait supprimé sauf pour test/dir/dir/file qui est le plus important à 50 octets.

test 
|-- [ 26] file 
|-- [ 4096] dir 
| |-- [ 34] file 
`-- [ 4096] dir 
    |-- [ 4096] dir 
    | |-- [ 50] file 
    `-- [ 4096] test 
     `-- [ 4096] dir 
      `-- [ 20] file 
+0

Nous avons vraiment besoin d'ajouter --head/- tail ou équivalent pour trier. Ce serait à la fois fonctionnel et algorithmique – pixelbeat

+0

Oui, je pense que je suis d'accord. Il a déjà '-u' pour unique, donc il semblerait être un bon ajustement. –