Gibt es eine Möglichkeit, Duplikate zu löschen, die verfeinerter sind als fdupes -rdN?

22

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. Zunächst fdupesschien es das beste Werkzeug für den 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 es auf Duplikate stößt, werden diese gelöscht, sodass nur eine Kopie von allem vorhanden ist.

Aber was ist, wenn ich es behalten möchte somedirectory/subdirectory1/somefileund tatsächlich vier Duplikate vorhanden sind und das Programm zuerst auf eines der Duplikate stößt? Dann löscht es somedirectory/subdirectory1/somefile, was ich nicht will.

Ich möchte in der Lage sein, irgendwie anzugeben, welche Duplikate aufbewahrt werden sollen. Und bisher scheint keines der Standardprogramme für den Umgang mit Duplikaten (Duff, FSLint) eine Automatisierung dieser Art von Verhalten zu ermöglichen. Ich würde es vorziehen, nicht meine eigene Rolle zu spielen, deshalb stelle ich diese Frage.

Ich würde gerne in der Lage sein, so etwas zu schreiben

killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/
ixtmixilix
quelle
Ich suchte das Gleiche und fand dieses superuser.com/a/561207/218922
alexis

Antworten:

5

Obwohl die von Ihnen gesuchte Funktionalität nicht auf Lager verfügbar ist fdupes, habe ich nachgegeben fdupes (meine Gabel heißt jdupes) und einige Funktionen hinzugefügt, die dieses Problem unter bestimmten Umständen lösen können. In dem angegebenen Fall, in dem Sie beispielsweise somedirectory/subdirectory1/somefilebeim automatischen Löschen von Duplikaten (das dund Nwechselt zusammen) beibehalten möchten und sich keine separaten Dateien unmittelbar darunter befinden somedirectory, jdupeskönnen Sie jedem direkten Unterverzeichnispfad subdirectory1zuerst und dem -OSchalter (der die Dateien nach Befehlen sortiert) einen Eintrag zuweisen Parameterreihenfolge zuerst):

jdupes -nrdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3

Dies löscht automatisch alle bis auf eine Datei in einem doppelten Satz und somedirectory/subdirectory1stellt sicher, dass, wenn der Satz eine Datei enthält , diese die erste ist, wodurch sie automatisch zur konservierten Datei im Satz wird. Es gibt immer noch krasse Grenzen für diesen Ansatz, zum Beispiel die Tatsache, dass ein anderes Duplikat somedirectory/subdirectory1anstelle des von Ihnen gewünschten beibehalten werden kann, aber in einer guten Anzahl von Fällen wie Ihrem ist die jdupesOption für die Parameterreihenfolge als Workaround ausreichend.

In naher Zukunft plane ich, ein Filtersystem hinzuzufügen jdupes, das eine enorme Kontrolle über das Einschließen / Ausschließen von Dateien, die Aufbewahrung von -NAktionen und die Anwendung solcher "Filterstapel" auf globaler oder parameterbezogener Basis ermöglicht. Diese Funktion wird dringend benötigt. Ich stelle mir so etwas wie "Nicht-Null-Duplikate rekursiv automatisch löschen, ABER immer so aufbewahren, somedirectory/subdirectory1/somefilewie sie sind" vor:

jdupes -nrdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/

Jody Lee Bruchon
quelle
4

Was ist mit dem Zusammenfügen der doppelten Dateien? Auf diese Weise wird der Raum nur einmal verwendet, aber sie existieren immer noch in 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, indem die Datei gelöscht und mit dem neuen Inhalt neu erstellt wird). Der andere Ansatz besteht darin, die Dateien miteinander zu verknüpfen, obwohl Sie die gleiche Frage haben, welche die "primäre" Datei ist. Dies könnte mit dem folgenden Skript geschehen (obwohl dies keine Dateinamen behandelt, die Leerzeichen enthalten).

fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do
    for DEST in $DESTS; do
        ln -f $SOURCE $DEST
    done
done
mgorven
quelle
1
Verwenden Sie jdupesstatt fdupesSie können einfach gehen, jdupes -nrL somedirectory/was massiv schneller ist.
Jody Lee Bruchon
1
Tippfehler im Link zu jdupes. Convenience-Link: github.com/jbruchon/jdupes
Royce Williams
4

Ich habe das nirgendwo anders gesehen: Sagen Sie, was Sie wollen, ist das. Sie haben / mnt / folder-tree-1 / mnt / folder-tree-2. Sie möchten nicht jedes Duplikat entfernen, aber wenn in Baum-2 eine Datei vorhanden ist und in Baum-1 eine identische Datei mit genau demselben Pfad und Namen vorhanden ist, entfernen Sie sie aus Baum-2.

Achtung: 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 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

Überprüfen Sie anschließend die Datei rm-v2-dupes.sh und führen Sie sie aus

Gaute Lund
quelle
4

Ich hatte die gleiche frage Wenn Sie viele Duplikate haben, wird fdupes /my/directory/ -rdNdie Datei mit dem ältesten Änderungsdatum beibehalten, oder wenn mehrere Dateien das gleiche Änderungsdatum haben, wird die zuerst gefunden.

Wenn das Änderungsdatum für Sie nicht wichtig ist, können Sie touchdie Dateien in dem Verzeichnis speichern, das Sie behalten möchten. Wenn Sie touchsie mit dem aktuellen Datum und der aktuellen Uhrzeit auswählen, fdupes -rdNiwerden diejenigen mit dem aktuellen Datum beibehalten. Oder Sie können touchDateien mit einem früheren Datum als dem der zu löschenden behalten und fdupes -rdNwie gewohnt verwenden.

Wenn Sie das Änderungsdatum beibehalten müssen, müssen Sie eine der anderen Methoden anwenden.

Pheon
quelle
3

Nur um einer vorherigen Antwort eine Wendung hinzuzufügen. Ich habe den folgenden Code mehrmals verwendet und eine vorherige Antwort durch einfaches | grepIsolieren des Ordners, aus dem ich löschen möchte , leicht geändert .

`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, in der alle aufgelisteten Dateien ohne kommentierte Zeilen gelöscht werden. Natürlich können Sie die Datei auch weiterhin bearbeiten, um bestimmte Zeilen / Dateien, die Sie behalten möchten, zu kommentieren.

Ein weiterer Hinweis für große Verzeichnisse ist, fdupes in eine txt-Datei auszuführen und dann mit | grepund zu experimentieren, | sedbis das gewünschte Ergebnis vorliegt .

`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`
jfl
quelle
2

Verwenden Sie seddiese Option , um eine Shell-Datei zu erstellen, die auskommentierte Befehle zum Löschen jeder Ihrer doppelten Dateien enthält:

fdupes -r -n -S /directory | sed -r "s/^/#rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh

In der remove-duplicate-files.shsoeben erstellten resultierenden Datei ist jede Zeile auskommentiert. Kommentieren Sie die zu löschenden Dateien aus. Dann lauf sh remove-duplicate-files.sh. Voila!

AKTUALISIEREN

Wenn Sie Dateien nicht nur in bestimmten Verzeichnissen löschen möchten, ist dies so einfach :

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

Wo exclude_duplicates.pyist:

#/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)

In der remove-duplicate-files-keep-protected.shsoeben erstellten resultierenden Datei sind 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 es dann aus. Voila!

Ivan Kharlamov
quelle
Ich habe darüber nachgedacht, aber es ist nicht automatisiert genug. Dummerweise verursachte ich mit dieser Methode Datenverlust, wenn es um Duplikate ging, die über mehrere Dateisysteme verteilt waren. Angesichts der Ausgabe von fdupes gibt es keine Möglichkeit, eine Priorität zuzuweisen. im grunde hätte ich 10000 dateien von hand durchforsten müssen, um diesen datenverlust zu verhindern ... also nein danke ... in der tat ist dieser datenverlust der eigentliche grund, warum ich diese frage gestellt habe.
ixtmixilix
@ixtmixilix, na ja, manuelle Methode ist abhängig von der Aufmerksamkeit des Benutzers, hier ist nichts Neues. Wenn Sie etwas automatisierter möchten, lesen Sie die aktualisierte Antwort oben.
Ivan Kharlamov
2

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
Rynchodon
quelle