Il y a pas mal de problèmes dans votre script.
Premièrement, afin d'assigner le résultat d'une commande à une variable, vous devez l'enfermer soit dans backtics ( `command`
), soit de préférence $(command)
. Vous l'avez entre guillemets simples ( 'command'
) qui, au lieu d'affecter le résultat de votre commande à votre variable, affecte la commande elle-même sous forme de chaîne. Par conséquent, vous test
êtes en fait:
$ echo "test $sum1=$sum2"
test find $i -type f -iname "*.jpg" -exec md5sum {} \;=find $j -type f -iname "*.jpg" -exec md5sum {} \;
Le problème suivant est que la commande md5sum
renvoie plus que le hachage:
$ md5sum /etc/fstab
46f065563c9e88143fa6fb4d3e42a252 /etc/fstab
Vous souhaitez uniquement comparer le premier champ, vous devez donc analyser la md5sum
sortie en la passant par une commande qui imprime uniquement le premier champ:
find $i -type f -iname "*.png" -exec md5sum '{}' \; | cut -f 1 -d ' '
ou
find $i -type f -iname "*.png" -exec md5sum '{}' \; | awk '{print $1}'
De plus, la find
commande renverra de nombreuses correspondances, pas une seule et chacune de ces correspondances sera dupliquée par la seconde find
. Cela signifie qu'à un moment donné, vous comparerez le même fichier à lui-même, la somme md5 sera identique et vous finirez par supprimer tous vos fichiers (j'ai exécuté cela sur un répertoire de test contenant a.jpg
et b.jpg
):
for i in $(find . -iname "*.jpg"); do
for j in $(find . -iname "*.jpg"); do
echo "i is: $i and j is: $j"
done
done
i is: ./a.jpg and j is: ./a.jpg ## BAD, will delete a.jpg
i is: ./a.jpg and j is: ./b.jpg
i is: ./b.jpg and j is: ./a.jpg
i is: ./b.jpg and j is: ./b.jpg ## BAD will delete b.jpg
Vous ne voulez pas exécuter for i in directory_path
sauf si vous passez un tableau de répertoires. Si tous ces fichiers sont dans le même répertoire, vous souhaitez exécuter for i in $(find directory_path -iname "*.jpg"
) pour parcourir tous les fichiers.
C'est une mauvaise idée d'utiliser des for
boucles avec la sortie de find. Vous devez utiliser des while
boucles ou des globes :
find . -iname "*.jpg" | while read i; do [...] ; done
ou, si tous vos fichiers se trouvent dans le même répertoire:
for i in *jpg; do [...]; done
Selon votre shell et les options que vous avez définies, vous pouvez utiliser la globalisation même pour les fichiers dans les sous-répertoires, mais n'abordons pas cela ici.
Enfin, vous devez également citer vos variables, sinon les chemins de répertoire avec des espaces briseront votre script.
Les noms de fichiers peuvent contenir des espaces, de nouvelles lignes, des barres obliques inverses et d'autres caractères étranges, pour les traiter correctement dans une while
boucle, vous devrez ajouter quelques options supplémentaires. Ce que vous voulez écrire, c'est quelque chose comme:
find dir_path -type f -iname "*.jpg" -print0 | while IFS= read -r -d '' i; do
find dir_path -type f -iname "*.jpg" -print0 | while IFS= read -r -d '' j; do
if [ "$i" != "$j" ]
then
sum1=$(md5sum "$i" | cut -f 1 -d ' ' )
sum2=$(md5sum "$j" | cut -f 1 -d ' ' )
[ "$sum1" = "$sum2" ] && rm "$j"
fi
done
done
Une manière encore plus simple serait:
find directory_path -name "*.jpg" -exec md5sum '{}' + |
perl -ane '$k{$F[0]}++; system("rm $F[1]") if $k{$F[0]}>1'
Une meilleure version qui peut gérer les espaces dans les noms de fichiers:
find directory_path -name "*.jpg" -exec md5sum '{}' + |
perl -ane '$k{$F[0]}++; system("rm \"@F[1 .. $#F]\"") if $k{$F[0]}>1'
Ce petit script Perl passera par les résultats de la find
commande (ie le md5sum et le nom du fichier). L' -a
option de perl
fractionnement des lignes d'entrée à l'espace blanc et les enregistre dans le F
tableau, $F[0]
sera donc le md5sum et $F[1]
le nom de fichier. Le md5sum est enregistré dans le hachage k
et le script vérifie si le hachage a déjà été vu ( if $k{$F[0]}>1
) et supprime le fichier s'il a ( system("rm $F[1]")
).
Bien que cela fonctionne, cela sera très lent pour les grandes collections d'images et vous ne pouvez pas choisir les fichiers à conserver. Il existe de nombreux programmes qui gèrent cela de manière plus élégante, notamment: