Znajdź zduplikowane pliki

90

Czy na moim dysku można znaleźć duplikaty plików, które są identyczne bit po bicie, ale mają różne nazwy plików?

student
źródło
3
Zauważ, że każda możliwa metoda wykonania tego będzie niezmiennie musiała porównywać każdy pojedynczy plik w systemie z każdym innym plikiem . Zajmie to dużo czasu, nawet podczas korzystania ze skrótów.
Shadur
4
@Shadur, jeśli ktoś jest w porządku z sumami kontrolnymi, sprowadza się do porównania samych skrótów - które w większości systemów są rzędu 10 ^ (5 + -1), zwykle <64-bajtowe wpisy. Oczywiście musisz odczytać dane przynajmniej raz. :)
Peter
15
@Shadur To nieprawda. Możesz skrócić czas, sprawdzając pasujące st_sizes, eliminując te, które mają tylko jedno takie same, a następnie obliczając tylko sumy md5 dla pasujących st_sizes.
Chris Down,
6
@Shadur nawet niezwykle głupie podejście uniemożliwiające jakiekolwiek operacje haszujące mogłoby to zrobić w Θ (n log n) porównuje - nie Θ (n²) - przy użyciu dowolnego z kilku algorytmów sortowania (w oparciu o zawartość pliku).
derobert
1
@ChrisDown Tak, dopasowanie rozmiaru byłoby jednym ze skrótów, które miałem na myśli.
Shadur

Odpowiedzi:

104

fdupesmogę to zrobić. Od man fdupes:

Przeszukuje podaną ścieżkę w poszukiwaniu duplikatów plików. Takie pliki można znaleźć, porównując rozmiary plików i sygnatury MD5, a następnie porównując bajt po bajcie.

W Debianie lub Ubuntu możesz go zainstalować przy pomocy apt-get install fdupes. W Fedorze / Red Hat / CentOS możesz go zainstalować za pomocą yum install fdupes. Na Arch Linux można użyć pacman -S fdupes, a na Gentoo emerge fdupes.

Aby uruchomić czek malejący z katalogu głównego systemu plików, co prawdopodobnie zajmie dużo czasu i pamięci, użyj czegoś takiego fdupes -r /.

Jak podano w komentarzach, możesz uzyskać największe duplikaty, wykonując następujące czynności:

fdupes -r . | {
    while IFS= read -r file; do
        [[ $file ]] && du "$file"
    done
} | sort -n

To się zepsuje, jeśli twoje nazwy plików zawierają nowe linie.

Chris Down
źródło
Dzięki. Jak mogę odfiltrować największy duplikat? Jak sprawić, by rozmiary były czytelne dla człowieka?
student
@student: użyj czegoś wzdłuż linii (upewnij się, że fdupes po prostu wyświetla nazwy plików bez dodatkowych informacji lub wycinania lub sedowania, aby to zachować): fdupes ....... | xargs ls -alhd | egrep 'M |G 'aby zachować pliki w formacie czytelnym dla ludzi i tylko te o rozmiarze w megabajtach lub gigabajtach. Zmień polecenie, aby odpowiadało rzeczywistym wynikom.
Olivier Dulac
2
@OlivierDulac Nigdy nie powinieneś analizować ls . Zwykle jest gorzej niż w twoim przypadku użycia, ale nawet w twoim przypadku użycia ryzykujesz fałszywie dodatnie.
Chris Down,
@student - Gdy już masz nazwy plików, dupotok do sortpowie ci.
Chris Down,
@ChrisDown: to prawda, że ​​to zły nawyk i może dawać fałszywe alarmy. Ale w tym przypadku (użycie interaktywne i tylko do wyświetlania, bez „rm” lub cokolwiek innego bezpośrednio na nim polegającego) jest w porządku i szybkie ^^. Kocham te strony, które zawierają linki do, btw (czytam je od kilku miesięcy, a pełne informacje o wielu użytecznych)
Olivier Dulac
26

Kolejnym dobrym narzędziem jest fslint:

fslint to zestaw narzędzi do znajdowania różnych problemów z systemami plików, w tym duplikatów plików i problematycznych nazw plików itp.

Poszczególne narzędzia wiersza poleceń są dostępne oprócz GUI i aby uzyskać do nich dostęp, można zmienić lub dodać do $ PATH katalog / usr / share / fslint / fslint podczas standardowej instalacji. Każde z tych poleceń w tym katalogu ma opcję --help, która bardziej szczegółowo opisuje jego parametry.

   findup - find DUPlicate files

W systemach opartych na Debianie możesz zainstalować go z:

sudo apt-get install fslint

Możesz to zrobić ręcznie, jeśli nie chcesz lub nie możesz zainstalować narzędzi innych firm. Większość takich programów działa poprzez obliczanie sum kontrolnych plików . Pliki z tym samym md5sum prawie na pewno zawierają dokładnie te same dane. Więc możesz zrobić coś takiego:

find / -type f -exec md5sum {} \; > md5sums
gawk '{print $1}' md5sums | sort | uniq -d > dupes
while read d; do echo "---"; grep $d md5sums | cut -d ' ' -f 2-; done < dupes 

Przykładowe dane wyjściowe (nazwy plików w tym przykładzie są takie same, ale zadziała również, gdy będą różne):

$ while read d; do echo "---"; grep $d md5sums | cut -d ' ' -f 2-; done < dupes 
---
 /usr/src/linux-headers-3.2.0-3-common/include/linux/if_bonding.h
 /usr/src/linux-headers-3.2.0-4-common/include/linux/if_bonding.h
---
 /usr/src/linux-headers-3.2.0-3-common/include/linux/route.h
 /usr/src/linux-headers-3.2.0-4-common/include/linux/route.h
---
 /usr/src/linux-headers-3.2.0-3-common/include/drm/Kbuild
 /usr/src/linux-headers-3.2.0-4-common/include/drm/Kbuild
---

Będzie to znacznie wolniejsze niż wspomniane już dedykowane narzędzia, ale zadziała.

terdon
źródło
4
Byłoby o wiele, znacznie szybciej znaleźć pliki o tym samym rozmiarze, co inny plik st_size, eliminując te, które mają tylko jeden plik o tym rozmiarze, a następnie obliczając sumy md5 tylko między plikami o tym samym rozmiarze st_size.
Chris Down,
@ChrisDown tak, chciałem tylko, żeby było to proste. To, co sugerujesz, znacznie przyspieszy sprawę. Dlatego mam zastrzeżenie, że jest wolne na końcu mojej odpowiedzi.
terdon
8

Krótka odpowiedź: tak.

Dłuższa wersja: spójrz na wpis w Wikipedii fdupes , zawiera całkiem niezłą listę gotowych rozwiązań. Oczywiście można napisać własną rękę, nie jest to , że trudno - programy mieszaja jak diff, sha*sum, find, sorti uniqpowinno załatwić sprawę. Możesz nawet umieścić go w jednym wierszu i nadal będzie to zrozumiałe.

Peter
źródło
6

Jeśli uważasz, że funkcja skrótu (tutaj MD5) jest wolna od kolizji w Twojej domenie:

find $target -type f -exec md5sum '{}' + | sort | uniq --all-repeated --check-chars=32 \
 | cut --characters=35-

Chcesz pogrupować identyczne nazwy plików? Napisz prosty skrypt, not_uniq.shaby sformatować dane wyjściowe:

#!/bin/bash

last_checksum=0
while read line; do
    checksum=${line:0:32}
    filename=${line:34}
    if [ $checksum == $last_checksum ]; then
        if [ ${last_filename:-0} != '0' ]; then
            echo $last_filename
            unset last_filename
        fi
        echo $filename
    else
        if [ ${last_filename:-0} == '0' ]; then
            echo "======="
        fi
        last_filename=$filename
    fi

    last_checksum=$checksum
done

Następnie zmień findpolecenie, aby użyć skryptu:

chmod +x not_uniq.sh
find $target -type f -exec md5sum '{}' + | sort | not_uniq.sh

To jest podstawowy pomysł. Prawdopodobnie powinieneś zmienić, findjeśli twoje nazwy plików zawierają niektóre znaki. (np. spacja)

xin
źródło
6

Pomyślałem, aby dodać niedawno ulepszony rozwidlenie fdupes, jdupes , które zapowiadają się szybciej i będą bardziej bogate w funkcje niż fdupes (np. Filtr rozmiaru):

jdupes . -rS -X size-:50m > myjdups.txt

Spowoduje to rekurencyjne odnalezienie zduplikowanych plików większych niż 50 MB w bieżącym katalogu i wygenerowanie listy wyników w myjdups.txt.

Uwaga: dane wyjściowe nie są sortowane według rozmiaru, a ponieważ wydaje się, że nie są wbudowane, dostosowałem odpowiedź @Chris_Down powyżej, aby to osiągnąć:

jdupes -r . -X size-:50m | {
    while IFS= read -r file; do
        [[ $file ]] && du "$file"
    done
} | sort -n > myjdups_sorted.txt
Sebastian Müller
źródło
Uwaga: najnowsza wersja jdupes obsługuje dopasowanie plików z tylko częściowym haszowaniem zamiast oczekiwania na haszowanie całego. Bardzo przydatne. (Musisz sklonować archiwum git, aby je zdobyć.) Oto opcję, z której korzystam teraz: jdupes -r -T -T --exclude = rozmiar-: 50m
Benjamin
2

Wikipedia miała artykuł ( http://en.wikipedia.org/wiki/List_of_duplicate_file_finders ) z listą dostępnego oprogramowania typu open source do tego zadania, ale teraz zostało usunięte .

Dodam, że wersja fslint w GUI jest bardzo interesująca, pozwalając na użycie maski do wyboru plików do usunięcia. Bardzo przydatne do czyszczenia zduplikowanych zdjęć.

W systemie Linux możesz użyć:

- FSLint: http://www.pixelbeat.org/fslint/

- FDupes: https://en.wikipedia.org/wiki/Fdupes

- DupeGuru: https://www.hardcoded.net/dupeguru/

2 ostatnie prace na wielu systemach (Windows, Mac i Linux) Nie sprawdziłem FSLint

MordicusEtCubitus
źródło
5
Lepiej podać tutaj rzeczywiste informacje, a nie tylko link, link może się zmienić, a wtedy odpowiedź nie będzie miała żadnej wartości
Anthon
2
Strona Wikipedii jest pusta.
ihor_dvoretskyi
tak, zostało wyczyszczone, jaka szkoda wstrząsnąć ...
MordicusEtCubitus
Edytowałem go za pomocą tych 3 narzędzi
MordicusEtCubitus,
0

Oto moje zdanie na ten temat:

find -type f -size +3M -print0 | while IFS= read -r -d '' i; do
  echo -n '.'
  if grep -q "$i" md5-partial.txt; then echo -e "\n$i  ---- Already counted, skipping."; continue; fi
  MD5=`dd bs=1M count=1 if="$i" status=noxfer | md5sum`
  MD5=`echo $MD5 | cut -d' ' -f1`
  if grep "$MD5" md5-partial.txt; then echo "\n$i  ----   Possible duplicate"; fi
  echo $MD5 $i >> md5-partial.txt
done

Różni się tym, że zawiera tylko pierwsze 1 MB pliku.
Ma to kilka problemów / funkcji:

  • Może być różnica po pierwszych 1 MB, więc wynik raczej kandydat do sprawdzenia. Mogę to naprawić później.
  • Sprawdzanie najpierw według rozmiaru pliku może to przyspieszyć.
  • Pobiera tylko pliki większe niż 3 MB.

Używam go do porównywania klipów wideo, więc to mi wystarcza.

Ondra Žižka
źródło