Знайдіть дублікати файлів


90

Чи можна на моєму диску знайти дублікати файлів, які є бітовими ідентичними, але мають різні назви файлів?


3
Зауважте, що будь-який можливий спосіб зробити це незмінно доведеться порівнювати кожен окремий файл у вашій системі з кожним іншим файлом . Тож це займе багато часу, навіть якщо брати ярлики.
Шадур

4
@Shadur, якщо з контрольними сумами все нормально, це зводиться до порівняння лише хешів - що в більшості систем порядку 10 ^ (5 + -1) зазвичай <64-байтних записів. Звичайно, вам доведеться хоча б раз прочитати дані. :)
peterph

15
@Shadur Це неправда. Ви можете скоротити час, перевіривши відповідність st_sizes, вилучивши ті, що мають лише одне і те ж, і лише обчисливши md5суми для відповідності st_sizes.
Кріс Даун

6
@Shadur навіть неймовірно нерозумний підхід, забороняючи будь-які хеш-операції, може зробити це в in (n log n) порівняннях, а не Θ (n²), використовуючи будь-який з декількох алгоритмів сортування (на основі вмісту файлу).
дероберт

1
@ChrisDown Так, відповідність розміру була б одним із ярликів, які я мав на увазі.
Шадур

Відповіді:


104

fdupesможе це зробити. Від man fdupes:

Шукає заданий шлях для копій файлів. Такі файли знаходять, порівнюючи розміри файлів і підписи MD5 з подальшим порівнянням байт-байт.

У Debian або Ubuntu ви можете встановити його apt-get install fdupes. У Fedora / Red Hat / CentOS ви можете встановити його yum install fdupes. На Arch Linux можна використовувати pacman -S fdupes, а на Gentoo - emerge fdupes.

Щоб запустити чек, що походить від кореня вашої файлової системи, що, ймовірно, займе значну кількість часу та пам'яті, використовуйте щось на кшталт fdupes -r /.

Як просять у коментарях, ви можете отримати найбільші дублікати, виконавши наступні дії:

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

Це порушиться, якщо ваші імена файлів містять нові рядки.


Дякую. Як я можу відфільтрувати найбільший дуп? Як я можу зробити людські розміри читабельними?
студент

@student: використовуйте щось уздовж лінії (переконайтесь, що fdupes просто виводить назви файлів без зайвих інформатинів, або вирізати або sed, щоб просто зберегти це): fdupes ....... | xargs ls -alhd | egrep 'M |G 'для збереження файлів у читаному для людини форматі та лише тих, які мають розмір у Мегабайт або Гігабайт. Змініть команду відповідно до реальних результатів.
Олів'є Дулак

2
@OlivierDulac Ніколи не слід розбирати ls . Зазвичай це гірше, ніж у випадку використання, але навіть у випадку використання ви ризикуєте помилково позитивно.
Кріс Даун

@student - Після того, як у вас з'явиться ім'я файлів, duвам sortпотрібно сказати.
Кріс Даун

@ChrisDown: це правда, це шкідлива звичка і може дати помилкові позитиви. Але в цьому випадку (інтерактивне використання та лише для відображення жодних "rm" чи нічого подібного, що безпосередньо покладається на нього), це добре і швидко ^^. Мені подобаються ті сторінки, на які ви посилаєтесь, btw (читаю їх з декількох місяців і сповнені багатьох корисних відомостей)
Олів'є Дулак

26

Ще одним хорошим інструментом є fslint:

fslint - це набір інструментів для пошуку різних проблем з файловими системами, включаючи повторювані файли та проблемні назви файлів тощо.

Окремі інструменти командного рядка доступні на додаток до графічного інтерфейсу і для доступу до них можна змінити або додати до $ PATH каталог / usr / share / fslint / fslint при стандартній установці. Кожна з цих команд у цьому каталозі має опцію --help, яка детальніше деталізує її параметри.

   findup - find DUPlicate files

У системах на базі debian ви можете встановити його за допомогою:

sudo apt-get install fslint

Ви також можете це зробити вручну, якщо ви не хочете або не можете встановити сторонні інструменти. Спосіб роботи більшості таких програм - це обчислення контрольних сум файлів . Файли з тим самим md5sum майже напевно містять абсолютно однакові дані. Отже, ви можете зробити щось подібне:

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 

Вибірка зразка (назви файлів у цьому прикладі однакові, але вони також працюватимуть, коли вони різні):

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

Це буде набагато повільніше, ніж спеціальні інструменти, про які вже говорилося, але це спрацює.


4
Було б набагато, набагато швидше знайти будь-які файли такого ж розміру, як інший файл, використовуючи st_size, вилучивши будь-який, який має лише один файл такого розміру, а потім обчислити md5sums лише між файлами з однаковим файлом st_size.
Кріс Даун

@ChrisDown Так, просто хотілося зробити це просто. Те, що ви пропонуєте, значно пришвидшить ситуацію. Ось чому я маю відмову від того, що вона є повільною в кінці своєї відповіді.
terdon

8

Коротка відповідь: так.

Більш довга версія: подивіться на запис у вікіпедії fdupes , у ній є гарний список готових рішень. Звичайно , ви можете написати свій власний, це не що складно - хешування програми , такі як diff, sha*sum, find, sortі uniqповинен робити цю роботу. Можна навіть поставити його в одну лінію, і це все одно буде зрозуміло.


6

Якщо ви вважаєте, що хеш-функція (тут MD5) у вашому домені відсутня зіткнення:

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

Ви хочете згрупувати однакові імена файлів? Напишіть простий сценарій not_uniq.shдля форматування виводу:

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

Потім змініть findкоманду, щоб використовувати ваш сценарій:

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

Це основна ідея. Можливо, вам слід змінити, findякщо імена ваших файлів містять деякі символи. (наприклад, простір)


6

Я думав додати нещодавню розширену вилку fdupes, jdupes , яка обіцяє бути швидшою та більш функціональною, ніж fdupes (наприклад, фільтр розміру):

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

Це буде рекурсивно знаходити дублюючі файли розміром більше 50 Мб у поточному каталозі та виводить отриманий список у myjdups.txt.

Зауважте, вихід не сортується за розміром, і оскільки він, здається, не будується, я адаптував відповідь @Chris_Down вище, щоб досягти цього:

jdupes -r . -X size-:50m | {
    while IFS= read -r file; do
        [[ $file ]] && du "$file"
    done
} | sort -n > myjdups_sorted.txt

Примітка: остання версія jdupes підтримує відповідні файли лише з частковим хешем, замість того, щоб чекати хешування всього. Дуже корисний. (Вам потрібно клонувати архів git, щоб отримати його.) Ось варіант, який я зараз використовую: jdupes -r -T -T --exclude = size-: 50m --nohidden
Benjamin

2

У Вікіпедії була стаття ( http://en.wikipedia.org/wiki/List_of_duplicate_file_finders ) зі списком доступного програмного забезпечення з відкритим кодом для цього завдання, але воно тепер було видалено .

Додам, що версія fslint GUI дуже цікава, що дозволяє використовувати маску, щоб вибрати, які файли видалити. Дуже корисно прибирати дублювані фотографії.

У Linux ви можете використовувати:

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

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

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

Дві останні роботи в багатьох системах (windows, mac та linux) Я не перевірив FSLint


5
Тут краще надати фактичну інформацію, а не лише посилання, посилання може змінитися, і тоді відповідь не має значення
Антон

2
Сторінка Вікіпедії порожня.
ihor_dvoretskyi

так, прибрано, як шкода трясти ...
MordicusEtCubitus

Я відредагував це за допомогою цих 3-х інструментів
MordicusEtCubitus

0

Ось мій погляд на це:

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

Він відрізняється тим, що він хеширує до перших 1 Мб файлу.
У цьому мало питань / особливостей:

  • Може виникнути різниця після першого 1 Мб, тому результат швидше кандидат перевірити. Я можу це виправити пізніше.
  • Спочатку перевірка розміру файлу може прискорити це.
  • Займається лише файлами розміром більше 3 Мб.

Я використовую його для порівняння відеороликів, щоб цього мені достатньо.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.