Ich habe ein Verzeichnis mit mehreren IMG-Dateien und einige von ihnen sind identisch, aber sie haben alle unterschiedliche Namen. Ich muss Duplikate entfernen, aber ohne externe Tools nur mit einem bash
Skript. Ich bin ein Anfänger in Linux. Ich habe versucht, verschachtelte for-Schleifen zu vergleichen md5
und je nach Ergebnis zu entfernen, aber etwas stimmt mit der Syntax nicht und es funktioniert nicht. irgendeine Hilfe?
was ich versucht habe ist ...
for i in directory_path; do
sum1='find $i -type f -iname "*.jpg" -exec md5sum '{}' \;'
for j in directory_path; do
sum2='find $j -type f -iname "*.jpg" -exec md5sum '{}' \;'
if test $sum1=$sum2 ; then rm $j ; fi
done
done
Ich bekomme: test: too many arguments
bash
shell-script
linuxbegin
quelle
quelle
Antworten:
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 Ihrtest
eigentlich:Das nächste Problem ist, dass der Befehl
md5sum
mehr als nur den Hash zurückgibt: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:oder
Außerdem gibt der
find
Befehl viele Übereinstimmungen zurück, nicht nur eine, und jede dieser Übereinstimmungen wird von der zweiten dupliziertfind
. 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, dasa.jpg
und enthältb.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ührenfor 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 solltenwhile
Schleifen oder Globbing verwenden :oder, wenn sich alle Ihre Dateien in demselben Verzeichnis befinden:
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:Ein noch einfacherer Weg wäre:
Eine bessere Version, die mit Leerzeichen in Dateinamen umgehen kann:
Dieses kleine Perl-Skript durchläuft die Ergebnisse des
find
Befehls (dh die MD5-Summe und den Dateinamen). Die-a
Option zumperl
Teilen von Eingabezeilen mit Leerzeichen und zum Speichern imF
Array enthält$F[0]
die MD5-Summe und$F[1]
den Dateinamen. Die md5sum wird im Hash gespeichertk
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:
fdupes
fslint
quelle
unlink
anstatt einensystem
Anruf zu tätigen.$F[1]
. Problem mit Array-Slices behoben. Ich kenne unlink (), wollte aber die Perlismen auf ein Minimum beschränken, und der Systemaufruf ist einfacher zu verstehen, wenn Sie Perl nicht kennen.Es gibt ein raffiniertes Programm,
fdupes
das den gesamten Vorgang vereinfacht und den Benutzer zum Löschen von Duplikaten auffordert. Ich denke, es lohnt sich zu überprüfen:Im Grunde wurde ich aufgefordert, die zu speichernde Datei auszuwählen . Ich gab 1 ein und entfernte die zweite.
Andere interessante Optionen sind:
In Ihrem Beispiel möchten Sie es wahrscheinlich ausführen als:
Siehe
man fdupes
für alle Optionen zur Verfügung.quelle