In letzter Zeit muss ich viele Duplikate löschen. Ich füge drei oder vier Dateisysteme zusammen und möchte, dass der Speicherplatz wirtschaftlich genutzt wird. Anfangs schien fdupes
das beste Werkzeug für diesen Job zu sein, aber ich stoße zunehmend auf Einschränkungen.
Betrachten Sie den Befehl fdupes -rdN somedirectory/
. Dadurch wird ein Hash aller Dateien in den Unterverzeichnissen eines Verzeichnisses erstellt.
Und wenn Duplikate gefunden werden, werden sie gelöscht, sodass nur eine Kopie von allem vorhanden ist.
Aber was ist, wenn ich somedirectory/subdirectory1/somefile
und es gibt tatsächlich vier Duplikate, und das Programm trifft zuerst auf eines der Duplikate? Dann wird somedirectory/subdirectory1/somefile
gelöscht, was ich nicht möchte.
Ich möchte irgendwie angeben können, welche Duplikate beibehalten werden sollen. Und bisher keine der Standardprogramme für den Umgang mit Duplikaten (duff, FSLint) scheinen eine Automatisierung dieser Art von Verhalten zu ermöglichen. Ich würde es vorziehen, mein eigenes nicht zu rollen, deshalb stelle ich diese Frage.
Ich möchte in der Lage sein, so etwas wie
killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/
Kommentare
- zu schreiben auf der Suche nach dem gleichen und fand ich diese superuser.com/a/561207/218922
Antwort
Während die von Ihnen gesuchte Funktionalität nicht auf Lager verfügbar ist fdupes
, gabelte ich fdupes
(meine Gabel heißt jdupes
) und fügte einige Funktionen hinzu, die dieses Problem unter bestimmten Umständen lösen können Beispiel: In dem angegebenen Fall, in dem Sie beim automatischen Löschen von Duplikaten (die d
und N
wechseln zusammen) und es befinden sich keine separaten Dateien direkt unter somedirectory
, jdupes
kann jedem unmittelbaren Unterverzeichnispfad mit subdirectory1
zuerst und der -O
-Schalter (der Dateien zuerst nach Befehlszeilenparameterreihenfolge sortiert):
jdupes -nrdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3
Dies löscht alle bis auf eine Datei in einem doppelten Satz automatisch und garantiert, dass der Satz, wenn er eine Datei in somedirectory/subdirectory1
enthält, die erste ist und automatisch zur erhaltenen Datei im Satz wird . Diesem Ansatz sind immer noch eklatante Grenzen gesetzt, z. B. die Tatsache, dass ein anderes Duplikat in somedirectory/subdirectory1
möglicherweise anstelle desjenigen beibehalten wird, das Sie behalten möchten, aber in vielen Fällen wie Ihrem. Die Parameterreihenfolge jdupes
als Problemumgehung ist ausreichend.
In naher Zukunft plane ich, ermöglicht eine umfassende Kontrolle über das Einschließen / Ausschließen von Dateien, die Aufbewahrung von -N
-Aktionen und die Anwendung solcher „Filterstapel“ entweder global oder per -Parameterbasis. Diese Funktion wird dringend benötigt. Ich stelle mir so etwas vor, um „Duplikate ungleich Null automatisch rekursiv automatisch zu löschen, ABER immer somedirectory/subdirectory1/somefile
wie sie sind“:
jdupes -nrdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/
Antwort
Ich habe diese nirgendwo anders gesehen: Sagen Sie, was Sie wollen, ist dies. Sie haben / mnt / Ordnerbaum-1 / mnt / Ordnerbaum-2. Sie möchten nicht jeden Betrüger entfernen, aber wenn eine Datei in Baum-2 vorhanden ist und eine identische Datei in Baum-1 mit genau derselben vorhanden ist Pfad und Name, entfernen Sie ihn aus Baum-2.
Warnung: Dies ist ziemlich knapp und wenn Sie versuchen, dies mit eingeschränkten Shell-Fähigkeiten zu kopieren und einzufügen, seien Sie vorsichtig.
fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line do if grep -q "`echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|"`" dupes-all.txt then echo rm \"$(echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2//|")\" fi done > rm-v2-dupes.sh
Oder alle in einer Zeile:
fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt; fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line; do if grep -q "`echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|"`" dupes-all.txt; then echo rm \"$(echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|")\"; fi; done > rm-v2-dupes.sh
Überprüfen Sie anschließend rm-v2-dupes.sh
und führen Sie es aus
Antwort
Wie wäre es, die doppelten Dateien miteinander zu verknüpfen? Auf diese Weise wird der Raum nur einmal verwendet, aber sie existieren immer noch auf allen Pfaden. Der Haken dabei ist, dass fest verknüpfte Dateien an Ort und Stelle geändert werden sollten (sie sollten nur geändert werden, um die Datei zu löschen und sie mit dem neuen Inhalt neu zu erstellen). Der andere Ansatz besteht darin, die Dateien miteinander zu verknüpfen, obwohl Sie das gleiche Problem bei der Entscheidung haben, um welche „primäre“ Datei es sich handelt. Dies kann mit dem folgenden Skript erfolgen (obwohl zu beachten ist, dass Dateinamen mit Leerzeichen nicht behandelt werden).
fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do for DEST in $DESTS; do ln -f $SOURCE $DEST done done
Kommentare
- Verwenden von
jdupes
anstelle vonfdupes
Sie können einfachjdupes -nrL somedirectory/
gehen, was sehr viel schneller ist. - Tippfehler im Link zu jdupes. Convenience-Link: github.com/jbruchon/jdupes
Antwort
Ich hatte dieselbe Frage.Wenn Sie viele Duplikate haben fdupes /my/directory/ -rdN
, behält die Datei das älteste Änderungsdatum bei, oder wenn mehrere Dateien dasselbe Änderungsdatum haben, wird zuerst das gefunden.
Wenn das Änderungsdatum für Sie nicht wichtig ist, können Sie touch
die Dateien in dem Verzeichnis speichern, das Sie behalten möchten. Wenn Sie touch
mit dem aktuellen Datum und der aktuellen Uhrzeit auswählen, behält fdupes -rdNi
die mit dem aktuellen Datum bei. Oder Sie können touch
die Aufbewahrungsdateien mit einem früheren Datum als dem der zu löschenden Dateien verwenden und fdupes -rdN
wie gewohnt verwenden. P. >
Wenn Sie das Änderungsdatum beibehalten müssen, müssen Sie eine der anderen Methoden verwenden.
Antwort
Nur um einer vorherigen Antwort eine Wendung hinzuzufügen. Ich habe den folgenden Code mehrmals verwendet und eine vorherige Antwort mit einer einfachen | grep
leicht geändert, um den Ordner zu isolieren, aus dem ich löschen möchte.
`fdupes -r -n -S /directory | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`
Auch hier wird eine sh-Datei erstellt, um alle aufgelisteten Dateien ohne kommentierte Zeilen zu löschen. Natürlich können Sie die Datei weiterhin bearbeiten, um bestimmte Zeilen / Dateien zu kommentieren, die Sie behalten möchten.
Ein weiterer Hinweis für große Verzeichnisse besteht darin, fdupes in einer txt-Datei auszuführen und dann mit | grep
und | sed
zu experimentieren, bis ich die erhalte Ergebnis, das ich möchte.
`fdupes -r -n -S /directory > duplicate-files.txt` `cat duplicate-files.txt | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`
Antwort
Verwenden Sie sed
, um eine Shell-Datei zu erstellen, die auskommentierte Befehle zum Löschen aller Ihrer Befehle enthält doppelte Dateien:
fdupes -r -n -S /directory | sed -r "s/^/#rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh
Die resultierende remove-duplicate-files.sh
fil Bei der soeben erstellten Zeile wird jede Zeile auskommentiert. Kommentieren Sie die Dateien aus, die Sie löschen möchten. Führen Sie dann sh remove-duplicate-files.sh
aus. Voila!
UPDATE
Wenn Sie Dateien nicht nur in bestimmten Verzeichnissen löschen möchten, ist dies so einfach wie folgt: :
fdupes -S /directory|sed "/^$/d" |sed -r "s/^[0-9]/#&/" > duple_list python exclude_duplicates.py -f /path/to/dupe_list --delimiter="#" --keep=/full/path/to/protected/directory1,/full/path/to/protected/directory2\ with\ spaces\ in\ path >remove-duplicate-files-keep-protected.sh
Wobei exclude_duplicates.py
ist:
#/usr/bin/python # -*- coding: utf-8 -*- # exclude_duplicates.py """ THE SCRIPT DOESN"T DELETE ANYTHING, IT ONLY GENERATES TEXT OUTPUT. Provided a list of duplicates, such as fdupes or fslint output, generate a bash script that will have all duplicates in protected directories commented out. If none of the protected duplicates are found in a set of the same files, select a random unprotected duplicate for preserving. Each path to a file will be transformed to an `rm "path"` string which will be printed to standard output. """ from optparse import OptionParser parser = OptionParser() parser.add_option("-k", "--keep", dest="keep", help="""List of directories which you want to keep, separated by commas. \ EXAMPLE: exclude_duplicates.py --keep /path/to/directory1,/path/to/directory\ with\ space\ in\ path2""", metavar="keep" ) parser.add_option("-d", "--delimiter", dest="delimiter", help="Delimiter of duplicate file groups", metavar="delimiter" ) parser.add_option("-f", "--file", dest="file", help="List of duplicate file groups, separated by delimiter, for example, fdupes or fslint output.", metavar="file" ) (options, args) = parser.parse_args() directories_to_keep = options.keep.split(",") file = options.file delimiter = options.delimiter pretty_line = "\n#" + "-" * 35 print "#/bin/bash" print "#I will protect files in these directories:\n" for d in directories_to_keep: print "# " + d print pretty_line protected_set = set() group_set = set() def clean_set(group_set, protected_set, delimiter_line): not_protected_set = group_set - protected_set while not_protected_set: if len(not_protected_set) == 1 and len(protected_set) == 0: print "#randomly selected duplicate to keep:\n#rm "%s"" % not_protected_set.pop().strip("\n") else: print "rm "%s"" % not_protected_set.pop().strip("\n") for i in protected_set: print "#excluded file in protected directory:\n#rm "%s"" % i.strip("\n") print "\n#%s" % delimiter_line file = open(file, "r") for line in file.readlines(): if line.startswith(delimiter): clean_set(group_set, protected_set, line) group_set, protected_set = set(), set() else: group_set = group_set|{line} for d in directories_to_keep: if line.startswith(d): protected_set = protected_set|{line} else: if line: clean_set(group_set, protected_set, line)
Die resultierende remove-duplicate-files-keep-protected.sh
-Datei werden alle Dateien aus geschützten Verzeichnissen auskommentiert. Öffnen Sie diese Datei in Ihrem bevorzugten Texteditor und überprüfen Sie, ob alles in Ordnung ist. Führen Sie sie dann aus. Voila (sic)!
Kommentare
- Ich habe darüber nachgedacht, aber ‚ ist nicht automatisiert genug. Dummerweise habe ich mit dieser Methode Datenverlust verursacht, als Umgang mit Duplikaten, die über mehrere Dateisysteme verteilt sind … ‚ kann angesichts der Ausgabe von fdup keine Priorität zuweisen es. Im Grunde hätte ich 10000 Dateien von Hand durchsuchen müssen, um diesen Datenverlust zu verhindern … also nein danke … in der Tat ist dieser Datenverlust genau der Grund, warum ich diese Frage gestellt habe.
- @ixtmixilix, nun, die manuelle Methode hängt von der Aufmerksamkeit des Benutzers ab. Hier ist ‚ nichts Neues. Wenn Sie etwas automatisierteres wünschen, lesen Sie oben eine aktualisierte Antwort.
Antwort
Was ist mit so etwas?
#!/bin/bash DUPE_SEARCH_DIR=somedir/ PREFERRED_DIRS=("somedir/subdir1" "somedir/subdir2") DUPE_FILE=/tmp/`basename $0`_found-duplicates delete_dupes() { while read line ; do if [ -n "$line" ] ; then matched=false for pdir in "${PREFERRED_DIRS[@]}" ; do if [[ $line == $pdir/* ]] ; then matched=true break fi done if ! $matched ; then rm -v "$line" fi fi done < "$DUPE_FILE" } cleanup() { rm -f $DUPE_FILE } trap cleanup EXIT # get rid of normal dupes, preserve first & preserve preferred fdupes -rf "$DUPE_SEARCH_DIR" > $DUPE_FILE delete_dupes # get rid of preserve dupes, preserve preferred fdupes -r "$DUPE_SEARCH_DIR" > "$DUPE_FILE" delete_dupes
Antwort
Ab dem Apple Filesystem (APFS) eine andere Lösung besteht darin, die Dateien zu behalten, sie zu deduplizieren und keine Auswirkungen auf die Festplattennutzung zu haben. Siehe Ersetzen Sie vorhandene doppelte Dateien in APFS durch Klone