Czy istnieje sposób na usunięcie duplikatów bardziej dopracowany niż fdupes -rdN?


22

Ostatnio muszę usunąć wiele duplikatów. Łączę trzy lub cztery systemy plików i chcę, aby przestrzeń była wykorzystywana ekonomicznie. Na początku fdupeswydawało się , że jest to najlepsze narzędzie do pracy, ale coraz częściej napotykam ograniczenia.

Rozważ polecenie fdupes -rdN somedirectory/. To tworzy skrót wszystkich plików w podkatalogach somedirectory.

A kiedy napotyka duplikaty, usuwa je, tak że istnieje tylko jedna kopia wszystkiego.

Ale co, jeśli chcę zachować, somedirectory/subdirectory1/somefilea w rzeczywistości są cztery duplikaty, a program najpierw napotka jeden z nich? Następnie usuwa somedirectory/subdirectory1/somefile, czego nie chcę.

Chcę móc w jakiś sposób określić, które duplikaty zachować. Jak dotąd żaden ze standardowych programów do radzenia sobie z duplikatami (duff, FSLint) nie pozwala na automatyzację tego rodzaju zachowań. Wolałbym nie toczyć własnego, dlatego zadaję to pytanie.

Chciałbym móc coś napisać

killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/

Szukałem tego samego i znalazłem tego superuser.com/a/561207/218922
Alexis

Odpowiedzi:


5

Chociaż szukana funkcjonalność nie jest dostępna w magazynie fdupes, rozwidliłem fdupes (nazywa się mój widelec jdupes) i dodałem pewne funkcje, które mogą rozwiązać ten problem w pewnych okolicznościach. Na przykład w podanym przypadku, gdy chcesz zachować somedirectory/subdirectory1/somefilepodczas automatycznego usuwania duplikatów ( di Nprzełącza się razem) i nie ma osobnych plików bezpośrednio pod nimi somedirectory, jdupesmożna podać subdirectory1pierwszą ścieżkę podkatalogu za pomocą pierwszego i -Oprzełącznika (który sortuje pliki według polecenia -pierwsza kolejność parametrów):

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

Spowoduje to automatyczne usunięcie wszystkich plików oprócz jednego w zduplikowanym zestawie i zagwarantuje, że jeśli zestaw zawiera plik somedirectory/subdirectory1, będzie to pierwszy plik, tym samym automatycznie stanie się zachowanym plikiem w zestawie. Nadal istnieją rażące ograniczenia tego podejścia, takie jak fakt, somedirectory/subdirectory1że można zachować inny duplikat zamiast tego, który chciałbyś zachować, ale w wielu przypadkach, takich jak Twoja, jdupesopcja porządkowania parametrów jako obejście jest wystarczająca.

W najbliższej przyszłości planuję dodać do jdupestego system filtrowania, który umożliwi ogromną kontrolę nad włączaniem / wykluczaniem plików, zachowaniem -Ndziałań i stosowaniem takich „stosów filtrów” na poziomie globalnym lub na parametr. Ta funkcja jest bardzo potrzebna; Wyobrażam sobie coś takiego w celu „automatycznego usuwania niezerowych duplikatów rekurencyjnie, ALE zawsze zachowuj somedirectory/subdirectory1/somefilejak jest”:

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


4

Co powiesz na łączenie zduplikowanych plików razem? W ten sposób przestrzeń jest wykorzystywana tylko raz, ale nadal istnieją na wszystkich ścieżkach. Problem polega na tym, że pliki dowiązane do sieci powinny być modyfikowane na miejscu (powinny być modyfikowane tylko poprzez usunięcie pliku i odtworzenie go z nową zawartością). Drugim podejściem jest łączenie plików razem, chociaż masz ten sam problem przy podejmowaniu decyzji, który plik „podstawowy” jest. Można to zrobić za pomocą następującego skryptu (chociaż należy pamiętać, że nie obsługuje to nazw plików zawierających spacje).

fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do
    for DEST in $DESTS; do
        ln -f $SOURCE $DEST
    done
done

1
Używanie jdupeszamiast fdupesciebie może po prostu iść, jdupes -nrL somedirectory/co jest znacznie szybsze.
Jody Lee Bruchon,

1
Literówka w łączu do jdupes. Link do wygody: github.com/jbruchon/jdupes
Royce Williams

4

Nigdzie indziej nie widziałem: Powiedz, co chcesz. Masz / mnt / folder-drzewo-1 / mnt / folder-drzewo-2. Nie chcesz usuwać każdego duplikatu, ale jeśli plik istnieje w drzewie-2, a identyczny plik istnieje w drzewie-1 o dokładnie tej samej ścieżce i nazwie, usuń go z drzewa-2.

Ostrzeżenie: to dość zwięzłe i jeśli spróbujesz skopiować i wkleić to z ograniczonymi umiejętnościami powłoki, bądź ostrożny.

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

Lub wszystkie w jednej linii:

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

Następnie sprawdź i uruchom plik rm-v2-dupes.sh


4

Miałem to samo pytanie. Jeśli masz wiele duplikatów, fdupes /my/directory/ -rdNzachowuje plik z najstarszą datą modyfikacji lub jeśli kilka plików ma tę samą datę modyfikacji, to ten znaleziony jako pierwszy.

Jeśli data modyfikacji nie jest dla Ciebie ważna, możesz touchpliki w katalogu, który chcesz zachować. Jeśli wybierzesz touchje z bieżącą datą i godziną fdupes -rdNi, zachowaj te z bieżącą datą. Możesz touchteż przechowywać pliki z datą wcześniejszą niż data, którą chcesz usunąć i używać fdupes -rdNjak zwykle.

Jeśli musisz zachować datę modyfikacji, musisz użyć jednej z pozostałych metod.


3

Wystarczy dodać zwrot do poprzedniej odpowiedzi. Użyłem następującego kodu wiele razy, nieznacznie modyfikując poprzednią odpowiedź, w prosty | grepsposób izolując folder, z którego chcę usunąć.

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

Ponownie utworzy to plik sh, aby usunąć wszystkie wymienione pliki bez wierszy z komentarzem. Oczywiście nadal możesz edytować plik, aby skomentować określone linie / pliki, które chcesz zachować.

Inną wskazówką dla dużych katalogów jest uruchomienie fdupes do pliku txt, a następnie eksperymentowanie z | grepi | seddopóki nie uzyskam pożądanego rezultatu.

`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`

2

Użyj, sedaby utworzyć plik powłoki, który będzie zawierał komentowane komentarze, aby usunąć każdy ze zduplikowanych plików:

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

Plik wynikowy remove-duplicate-files.sh, który właśnie utworzyliśmy, zostanie opatrzony komentarzem do każdego wiersza. Usuń komentarz z plików, które chcesz usunąć. Potem biegnij sh remove-duplicate-files.sh. Voila!

AKTUALIZACJA

Cóż, jeśli nie chcesz usuwać plików tylko w niektórych katalogach, jest to tak proste :

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

Gdzie exclude_duplicates.pyjest:

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

W remove-duplicate-files-keep-protected.shutworzonym pliku, który właśnie utworzyliśmy, wszystkie pliki z chronionych katalogów zostaną skomentowane. Otwórz ten plik w swoim ulubionym edytorze tekstu, sprawdź, czy wszystko jest w porządku. Następnie uruchom. Voila (sic)!


myślałem o tym, ale to nie jest wystarczająco zautomatyzowane. głupio, spowodowałem utratę danych tą metodą, gdy mamy do czynienia z duplikatami rozmieszczonymi w wielu systemach plików ... nie ma sposobu, aby przypisać priorytet, biorąc pod uwagę dane wyjściowe fdupes. w zasadzie musiałbym ręcznie przeszukać 10000 plików, aby zapobiec utracie danych ... więc nie, dziękuję ... w rzeczywistości utrata danych jest właśnie powodem, dla którego zadałem to pytanie.
ixtmixilix

@ixtmixilix, cóż, metoda ręczna zależy od uwagi użytkownika, oto nic nowego. Jeśli chcesz czegoś bardziej zautomatyzowanego, sprawdź zaktualizowaną odpowiedź powyżej.
Ivan Kharlamov

2

Co powiesz na coś takiego?

#!/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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.