Es gibt einige Probleme in Ihrem Skript.
Um das Ergebnis eines Befehls einer Variablen zuzuweisen , müssen Sie ihn zunächst entweder in backtics ( `command`
) oder vorzugsweise in. Einschließen $(command)
. Sie haben es in einfachen Anführungszeichen ( 'command'
), die den Befehl selbst als Zeichenfolge zuweisen, anstatt das Ergebnis Ihres Befehls Ihrer Variablen zuzuweisen. Daher ist Ihr test
eigentlich:
$ echo "test $sum1=$sum2"
test find $i -type f -iname "*.jpg" -exec md5sum {} \;=find $j -type f -iname "*.jpg" -exec md5sum {} \;
Das nächste Problem ist, dass der Befehl md5sum
mehr als nur den Hash zurückgibt:
$ md5sum /etc/fstab
46f065563c9e88143fa6fb4d3e42a252 /etc/fstab
Sie möchten nur das erste Feld vergleichen, daher sollten Sie die md5sum
Ausgabe analysieren, indem Sie einen Befehl ausführen, der nur das erste Feld druckt:
find $i -type f -iname "*.png" -exec md5sum '{}' \; | cut -f 1 -d ' '
oder
find $i -type f -iname "*.png" -exec md5sum '{}' \; | awk '{print $1}'
Außerdem gibt der find
Befehl viele Übereinstimmungen zurück, nicht nur eine, und jede dieser Übereinstimmungen wird von der zweiten dupliziert find
. Das bedeutet, dass Sie irgendwann dieselbe Datei mit sich selbst vergleichen, die MD5-Summe identisch ist und am Ende alle Ihre Dateien gelöscht werden (ich habe dies in einem Testverzeichnis ausgeführt, das a.jpg
und enthält 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
Sie möchten nicht ausgeführt werden, es for i in directory_path
sei denn, Sie übergeben ein Array von Verzeichnissen. Wenn sich alle diese Dateien in demselben Verzeichnis befinden, möchten Sie ausführen for i in $(find directory_path -iname "*.jpg"
, um alle Dateien zu durchsuchen.
Es ist eine schlechte Idee , for
Schleifen mit der Ausgabe von find zu verwenden. Sie sollten while
Schleifen oder Globbing verwenden :
find . -iname "*.jpg" | while read i; do [...] ; done
oder, wenn sich alle Ihre Dateien in demselben Verzeichnis befinden:
for i in *jpg; do [...]; done
Abhängig von Ihrer Shell und den von Ihnen festgelegten Optionen können Sie Globbing auch für Dateien in Unterverzeichnissen verwenden, aber darauf wollen wir hier nicht näher eingehen.
Schließlich sollten Sie auch Ihre Variablen in Anführungszeichen setzen, da sonst Verzeichnispfade mit Leerzeichen Ihr Skript beschädigen.
Dateinamen können Leerzeichen, neue Zeilen, umgekehrte Schrägstriche und andere seltsame Zeichen enthalten. Um diese in einer while
Schleife korrekt zu behandeln, müssen Sie einige weitere Optionen hinzufügen. Was Sie schreiben möchten, ist so etwas wie:
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
Ein noch einfacherer Weg wäre:
find directory_path -name "*.jpg" -exec md5sum '{}' + |
perl -ane '$k{$F[0]}++; system("rm $F[1]") if $k{$F[0]}>1'
Eine bessere Version, die mit Leerzeichen in Dateinamen umgehen kann:
find directory_path -name "*.jpg" -exec md5sum '{}' + |
perl -ane '$k{$F[0]}++; system("rm \"@F[1 .. $#F]\"") if $k{$F[0]}>1'
Dieses kleine Perl-Skript durchläuft die Ergebnisse des find
Befehls (dh die MD5-Summe und den Dateinamen). Die -a
Option zum perl
Teilen von Eingabezeilen mit Leerzeichen und zum Speichern im F
Array enthält $F[0]
die MD5-Summe und $F[1]
den Dateinamen. Die md5sum wird im Hash gespeichert k
und das Skript prüft, ob der Hash bereits gesehen wurde ( if $k{$F[0]}>1
) und löscht die Datei, falls vorhanden ( system("rm $F[1]")
).
Dies funktioniert zwar, ist jedoch für große Bildersammlungen sehr langsam und Sie können nicht auswählen, welche Dateien aufbewahrt werden sollen. Es gibt viele Programme, die auf elegantere Weise damit umgehen, darunter: