Найти дубликаты файлов

91

Возможно ли найти дубликаты файлов на моем диске, которые по битам идентичны, но имеют разные имена файлов?

ученик
источник
3
Обратите внимание, что любой возможный способ сделать это неизменно должен сравнивать каждый файл в вашей системе с каждым другим файлом . Так что это займет много времени, даже если вы используете ярлыки.
Шадур
4
@Shadur, если все в порядке с контрольными суммами, сводится к сравнению только хешей - которые в большинстве систем имеют порядок 10 ^ (5 + -1), обычно <64-байтовые записи. Конечно, вы должны прочитать данные хотя бы один раз. :)
Петер
15
@Shadur Это не правда. Вы можете сократить время, проверив совпадения st_sizes, исключив те из них, которые имеют только одно и то же, а затем вычислив только md5sums для сопоставления st_sizes.
Крис Даун
6
@Shadur, даже невероятно глупый подход, запрещающий любые операции хеширования, может сделать это в Θ (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 просто выводит имена файлов без дополнительной информации, или вырежьте или отредактируйте, чтобы просто сохранить это): fdupes ....... | xargs ls -alhd | egrep 'M |G 'чтобы сохранить файлы в удобочитаемом формате и только файлы с размером в мегабайтах или гигабайтах. Измените команду в соответствии с реальными результатами.
Оливье Дюлак
2
@OlivierDulac Вы никогда не должны анализировать ls . Обычно это хуже, чем ваш вариант использования, но даже в вашем случае вы рискуете получить ложные срабатывания.
Крис Даун
@student - После того, как у вас есть имена файлы, duконвейер sortвам скажут.
Крис Даун
@ChrisDown: это правда, это плохая привычка, которая может давать ложные срабатывания. Но в этом случае (интерактивное использование, и только для отображения, без «rm» или чего-либо подобного, прямо полагаясь на него) это хорошо и быстро ^^. Мне нравятся эти страницы, на которые вы ссылаетесь, кстати (я их читаю уже несколько месяцев и полна многих полезных сведений)
Оливье Дюлак
27

Еще один хороший инструмент fslint:

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

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

   findup - find DUPlicate files

В системах на основе Debian вы можете установить его с:

sudo apt-get install fslint

Вы также можете сделать это вручную, если вы не хотите или не можете установить сторонние инструменты. Большинство таких программ работают путем вычисления контрольных сумм файлов . Файлы с одинаковой суммой md5 почти наверняка содержат одинаковые данные. Итак, вы можете сделать что-то вроде этого:

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
Он может быть запущен на macOS, но вы должны заменить md5sum {}на md5 -q {}и gawk '{print $1}'сcat
Finesse
8

Краткий ответ: да.

Более длинная версия: взгляните на запись в wikipedia fdupes , она содержит довольно хороший список готовых решений. Конечно , вы можете написать свой собственный, это не что сложно - хэширования программы , такие как diff, sha*sum, find, sortи uniqдолжен делать эту работу. Вы можете даже поместить это в одну строку, и это все еще будет понятно.

peterph
источник
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
SurpriseDog
2

В Википедии была статья ( http://en.wikipedia.org/wiki/List_of_duplicate_file_finders ) со списком доступного программного обеспечения с открытым исходным кодом для этой задачи, но теперь она удалена .

Добавлю, что версия fslint с графическим интерфейсом очень интересна, позволяя использовать маску для выбора файлов для удаления. Очень полезно убирать дублированные фотографии.

В Linux вы можете использовать:

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

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

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

Последние 2 работы на многих системах (Windows, Mac и Linux) Я не проверен на FSLint

MordicusEtCubitus
источник
5
Здесь лучше предоставить актуальную информацию, а не просто ссылку, ссылка может измениться, и тогда ответ не имеет значения
Anthon
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 МБ.

Я использую его для сравнения видеоклипов, так что мне этого достаточно.

Ондра Жижка
источник