Ostatnio muszę usunąć wiele duplikatów. Scalam trzy lub cztery systemy plików i chcę, aby miejsce było wykorzystywane oszczędnie. Na początku fdupes wydawało się, że jest to najlepsze narzędzie do tego zadania, ale coraz częściej napotykam ograniczenia.

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

A kiedy napotka duplikaty, usuwa je, więc jest tylko jedna kopia wszystkiego.

Ale co, jeśli chcę zachować somedirectory/subdirectory1/somefile i faktycznie istnieją cztery duplikaty, a program napotyka jeden z nich jako pierwszy? Następnie usuwa somedirectory/subdirectory1/somefile, czego nie chcę.

Chcę móc w jakiś sposób określić, które duplikaty mają zachować. Jak dotąd żaden standardowych programów do pracy z duplikatami (duff, FSLint) wydaje się zezwalać na automatyzację tego rodzaju zachowań. Wolałbym nie tworzyć własnych, dlatego właśnie zadaję to pytanie.

Chciałbym móc napisać coś takiego jak

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

Komentarze

odpowiedź

Chociaż poszukiwana funkcja nie jest dostępna w magazynie fdupes, rozwidliłem fdupes (mój fork nazywa się jdupes) i dodał kilka funkcji, które mogą rozwiązać ten problem w określonych okolicznościach. na przykład w podanym przypadku, w którym chcesz zachować somedirectory/subdirectory1/somefile podczas automatycznego usuwania duplikatów (przełączniki d i N) i nie ma oddzielnych plików bezpośrednio pod somedirectory, jdupes mogą być zasilane każdą bezpośrednią ścieżką podkatalogu za pomocą subdirectory1 i -O przełącznik (który sortuje pliki według kolejności parametrów wiersza polecenia w pierwszej kolejności):

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

To automatycznie usunie wszystkie pliki z wyjątkiem jednego w zduplikowanym zestawie i zagwarantuje, że jeśli zestaw zawiera plik w somedirectory/subdirectory1, będzie to pierwszy plik, tym samym automatycznie stając się zachowanym plikiem w zestawie . Wciąż istnieją rażące ograniczenia, takie jak fakt, że inny duplikat w somedirectory/subdirectory1 może zostać zachowany zamiast tego, który chciałeś zachować, ale w wielu przypadkach, takich jak Twój, opcja kolejności parametrów jdupes jako obejście jest wystarczająco dobra.

W najbliższej przyszłości planuję dodać system filtrowania do jdupes, które umożliwi ogromną kontrolę nad włączaniem / wykluczaniem plików, zachowywaniem -N działań oraz stosowanie takich „stosów filtrów” na poziomie globalnym lub -podstawa parametrów. Ta funkcja jest bardzo potrzebna; Wyobrażam sobie coś takiego, aby „automatycznie usuwać niezerowe duplikaty rekurencyjnie, ALE zawsze zachowuj somedirectory/subdirectory1/somefile tak jak jest”:

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

Odpowiedź

Nie widziałem tego nigdzie indziej: Powiedz, czego chcesz. Masz / mnt / folder-tree-1 / mnt / folder-tree-2. Nie chcesz usuwać każdego duplikatu, ale jeśli plik istnieje w drzewie-2, a identyczny plik istnieje w drzewie-1 z dokładnie taką samą ścieżka i nazwa, usuń je 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 wszystko w jednym wierszu:

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 wykonaj rm-v2-dupes.sh

Odpowiedź

A co z połączeniem na stałe zduplikowanych plików? W ten sposób przestrzeń jest używana tylko raz, ale nadal istnieją na wszystkich ścieżkach. Haczyk polega na tym, że pliki dowiązane na stałe powinny być modyfikowane w miejscu (należy je modyfikować tylko usuwając plik i odtwarzając go z nową zawartością). Innym podejściem jest dowiązanie symboliczne plików do siebie, chociaż masz ten sam problem z podjęciem decyzji, który plik jest „podstawowy”. Można to zrobić za pomocą następującego skryptu (chociaż pamiętaj, że nie obsługuje on 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 

Komentarze

  • Używanie jdupes zamiast fdupes możesz po prostu przejść jdupes -nrL somedirectory/, co jest znacznie szybsze.
  • Literówka w linku do jdupes. Wygodny link: github.com/jbruchon/jdupes

Odpowiedź

Miałem to samo pytanie.Jeśli masz wiele duplikatów, fdupes /my/directory/ -rdN zachowuje 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 touch pliki w katalogu, który chcesz zachować. Jeśli wybierzesz touch je z bieżącą datą i godziną, fdupes -rdNi zachowa te z aktualną datą. Możesz też touch zachować pliki z datą wcześniejszą niż te, które chcesz usunąć, i używać fdupes -rdN jak zwykle.

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

Odpowiedź

Wystarczy dodać zwrot akcji do poprzedniej odpowiedzi. Wielokrotnie użyłem następującego kodu, nieznacznie modyfikując poprzednią odpowiedź za pomocą prostego | grep, aby wyodrębnić 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 komentowanych wierszy. Oczywiście nadal możesz edytować plik, aby skomentować określone wiersze / pliki, które chcesz zachować.

Inną wskazówką dotyczącą dużych katalogów jest uruchomienie fdupes do pliku txt, a następnie eksperymentowanie z | grep i | sed, aż otrzymam szukam wyniku.

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

Odpowiedź

Użyj sed , aby utworzyć plik powłoki, który będzie zawierał zakomentowane polecenia do usunięcia każdego z zduplikowane pliki:

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

Wynikowy remove-duplicate-files.sh fil Każdy wiersz, który właśnie utworzyliśmy, zostanie wykomentowany. Odkomentuj pliki, które chcesz usunąć. Następnie uruchom sh remove-duplicate-files.sh . Voila!

AKTUALIZACJA

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

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.py to:

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

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

Komentarze

  • Myślałem o tym, ale to ' nie jest wystarczająco zautomatyzowane. Głupio, spowodowałem utratę danych tą metodą, gdy radzenie sobie z duplikatami rozmieszczonymi na wielu systemach plików … tam ' nie ma możliwości przypisania priorytetu, biorąc pod uwagę wyjście fdup es. w zasadzie musiałbym ręcznie przeszukać 10000 plików, aby zapobiec utracie danych … więc nie, dziękuję … w rzeczywistości właśnie utrata danych jest powodem, dla którego zadałem to pytanie.
  • @ixtmixilix, cóż, metoda ręczna zależy od uwagi użytkownika, tutaj ' to nic nowego. Jeśli chcesz czegoś bardziej zautomatyzowanego, sprawdź zaktualizowaną odpowiedź powyżej.

Odpowiedź

A co z czymś takim?

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

Odpowiedź

W systemie plików Apple (APFS) inne rozwiązanie polega na zachowaniu plików, ich deduplikacji i bez wpływu na użycie dysku. Zobacz Zastąp istniejące zduplikowane pliki w APFS klonami

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *