
In letzter Zeit muss ich viele Duplikate löschen. Ich füge drei oder vier Dateisysteme zusammen und möchte den Speicherplatz wirtschaftlich nutzen. Zunächst fdupes
schien es das beste Tool für diese Aufgabe zu sein, aber ich stoße zunehmend an Grenzen.
Betrachten Sie den Befehl fdupes -rdN somedirectory/
. Dadurch wird ein Hash aller Dateien in den Unterverzeichnissen von somedirectory erstellt.
Und wenn es auf Duplikate stößt, löscht es diese, sodass von allem nur eine Kopie vorhanden ist.
Aber was, wenn ich behalten möchte somedirectory/subdirectory1/somefile
und es tatsächlich vier Duplikate gibt und das Programm zuerst auf eines der Duplikate stößt? Dann löscht es somedirectory/subdirectory1/somefile
, was ich nicht möchte.
Ich möchte irgendwie angeben können, welche Duplikate behalten werden sollen. Und bisher scheint keines der Standardprogramme zum Umgang mit Duplikaten (duff, FSLint) die Automatisierung dieser Art von Verhalten zu ermöglichen. Ich möchte lieber kein eigenes Programm entwickeln, deshalb stelle ich diese Frage.
Ich würde gerne so etwas schreiben können wie
killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/
Antwort1
Da die von Ihnen gesuchte Funktionalität nicht auf Lager ist fdupes
, habe ichfdupes
(meine Gabel heißt jdupes
)und einige Features hinzugefügt, die dieses Problem unter bestimmten Umständen lösen können. Im angegebenen Fall, in dem Sie beispielsweise somedirectory/subdirectory1/somefile
beim automatischen Löschen Duplikate beibehalten möchten (die Schalter d
und N
zusammen) und sich keine separaten Dateien direkt darunter befinden somedirectory
, jdupes
können Sie jeden unmittelbaren Unterverzeichnispfad subdirectory1
zuerst mit dem Schalter und dem -O
Schalter (der Dateien zuerst nach der Reihenfolge der Befehlszeilenparameter sortiert) füttern:
jdupes -rdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3
Dadurch werden alle Dateien bis auf eine in einem Duplikatssatz automatisch gelöscht. Außerdem wird garantiert, dass, wenn der Satz eine Datei enthält, somedirectory/subdirectory1
diese die erste ist und somit automatisch zur beibehaltenen Datei im Satz wird. Dieser Ansatz hat immer noch eklatante Einschränkungen, wie etwa die Tatsache, dass somedirectory/subdirectory1
möglicherweise ein anderes Duplikat beibehalten wird, anstatt das, das Sie behalten wollten. In vielen Fällen wie Ihrem jdupes
ist die Option der Parameterreihenfolge als Workaround jedoch ausreichend.
In naher Zukunft plane ich, ein Filtersystem hinzuzufügen, jdupes
das eine umfassende Kontrolle über die Einbeziehung/den Ausschluss von Dateien, die Beibehaltung für -N
Aktionen und die Anwendung solcher „Filterstapel“ entweder global oder pro Parameter ermöglicht. Diese Funktion wird dringend benötigt; ich stelle mir so etwas vor, um „Duplikate ungleich Null rekursiv automatisch zu löschen, ABER immer so zu erhalten, somedirectory/subdirectory1/somefile
wie sie sind“:
jdupes -rdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/
UPDATE (01.03.2022):Schauen Sie sich die -X
erweiterten Filteroptionen an, die im Jahr 2020 hinzugefügt wurden. Es ist nicht genau das, was Sie wollen, aber mit den - nostr
und onlystr
-Filtern können Sie Teilzeichenfolgen innerhalb eines vollständigen Pfads angeben, die ignoriert oder angefordert werden sollen.
Antwort2
Das habe ich nirgendwo sonst gesehen: Sagen Sie, was Sie wollen, ist Folgendes. Sie haben /mnt/Ordnerbaum-1 /mnt/Ordnerbaum-2. Sie wollen nicht jeden Duplikat entfernen, aber wenn eine Datei in Baum-2 existiert und eine identische Datei in Baum-1 mit genau demselben Pfad und Namen existiert, entfernen Sie sie aus Baum-2.
Achtung: Dies ist ziemlich knapp gehalten, und seien Sie vorsichtig, wenn Sie versuchen, es mit begrenzten Shell-Kenntnissen zu kopieren und einzufügen.
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 alles 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
Anschließend überprüfen und führen Sie rm-v2-dupes.sh aus.
Antwort3
Wie wäre es, die doppelten Dateien fest miteinander zu verknüpfen? Auf diese Weise wird der Speicherplatz nur einmal verwendet, aber sie sind immer noch in allen Pfaden vorhanden. Der Haken dabei ist, dass fest verknüpfte Dateien an Ort und Stelle geändert werden sollten (sie sollten nur geändert werden, indem die Datei gelöscht und mit dem neuen Inhalt neu erstellt wird). Der andere Ansatz besteht darin, die Dateien symbolisch miteinander zu verknüpfen, obwohl Sie das gleiche Problem haben, zu entscheiden, welche die „primäre“ Datei ist. Dies könnte mit dem folgenden Skript erfolgen (beachten Sie jedoch, dass dies keine Dateinamen mit Leerzeichen verarbeitet).
fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do
for DEST in $DESTS; do
ln -f $SOURCE $DEST
done
done
Antwort4
Nur um einer vorherigen Antwort eine Wendung zu geben. Ich habe den folgenden Code mehrmals verwendet und eine vorherige Antwort leicht modifiziert, um | grep
den Ordner, aus dem ich löschen möchte, einfach zu isolieren.
`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 zu löschen, keine auskommentierten Zeilen. Natürlich können Sie die Datei weiterhin bearbeiten, um bestimmte Zeilen/Dateien, die Sie behalten möchten, auskommentieren.
Ein weiterer Tipp für große Verzeichnisse besteht darin, fdupes in einer TXT-Datei auszuführen und dann damit zu experimentieren, | grep
bis | sed
ich das gewünschte Ergebnis erhalte.
`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`