Удалите дубликаты файлов, сравнивая их с MD5 рекурсивно

385
mandy

Я хочу удалить дубликаты файлов на основе их значения MD5. Я уже получил сценарий ниже, но как мне изменить его, чтобы он работал рекурсивно?

Так, например, у меня есть папка, содержащая 3 подпапки A B C

Я хочу, чтобы ВСЕ из этих файлов в ./ ./A/ ./B/ ./C/ проверялись на наличие md5 и сравнивались друг с другом, если найдено положительное совпадение, случайным образом удалите любое совпадение. В конце концов, больше нет дубликатов. Мне все равно, какой матч удаляется первым.

Я надеюсь, что я выразил то, что мне нужно, чтобы достичь достаточно ясно, если нет, пожалуйста, дайте мне знать :)

#!/bin/bash while true do echo "Enter the directory:" read directory if [ -d $directory ]; then break else echo "Invalid directory" fi done  for FILE in `ls $directory` do if [ ! -f $FILE ]; then break; fi h=`md5sum $directory/$FILE | awk '{ print $1 }'` for f in `ls $directory` do if [ -f $f ] && [ $FILE != $f ]; then s=`md5sum $directory/$f | awk '{ print $1 }'` if [ "$s" = "$h" ]; then echo Removing $f rm -rf $directory/$f fi fi done done 
0
Это сценарий? Существуют инструменты (например, `jdupes` или` fdupes` для Linux), которые идентифицируют дубликаты, жесткие ссылки или удаляют избыточные копии. Kamil Maciorowski 6 лет назад 2
Вы пытались использовать `find`? Вероятно, также стоит использовать `while read FILE` вместо` for FILE в $ (...) `для обработки массивных списков. Attie 6 лет назад 0
Спасибо за ваши ответы. Скрипт должен работать под Windows, а не Linux. Я думаю, что я не в том месте mandy 6 лет назад 0
Вы находитесь в хорошем месте, просто [отредактируйте] вопрос и четко объявите свою среду (WSL? Cygwin?) И цель (выполнение работы, независимо от инструмента? Или выполнение работы только с помощью Bash? И т. Д.) Kamil Maciorowski 6 лет назад 2
Сценарий, который вы показываете, для Linux ... Но производительность ужасна. Его производительность - O (n²), другими словами, вдвое больше файлов займет в четыре раза больше времени. Для 100 файлов md5sum будет запускаться 100.000 раз !!! , Я сомневаюсь, что это когда-либо действительно использовалось. xenoid 6 лет назад 1
@xenoid "_for Linux_" -> "_for bash_" Attie 6 лет назад 0
@attie С каких пор `md5sum` встроен в bash :) xenoid 6 лет назад 0
@xenoid что? это не ... с каких это пор "_linux only_"? OP предоставил "_bash script_", что видно по шебангу и тегу. Attie 6 лет назад 0

2 ответа на вопрос

1
StephenG

Во-первых, предостережение: предполагать идентичность на основе контрольной суммы очень опасно. Не рекомендуется.

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

Если бы я делал это, я бы подошел к этому так:

  1. Создать список файлов на основе длины (длина, полное имя пути)

  2. Отсканируйте этот список в поисках возможных повторяющихся длин.

  3. Любые совпадения являются потенциальными дубликатами, и я бы сравнил подозрительные файлы должным образом, если это возможно.

Причиной использования длин является то, что эта информация доступна очень быстро без побитового сканирования файла, как это обычно делается в статистике файловой системы для быстрого доступа.

Вы можете добавить еще один этап сравнения контрольных сумм (для файлов одинаковой длины), если считаете, что это быстрее, чем прямое сравнение файлов, используя аналогичный подход (контрольные суммы рассчитываются один раз). Используйте аналогичный подход (начните со списка совпадающих длин и вычислите контрольные суммы для них).

Выполнение вычисления контрольной суммы полезно только в том случае, если имеется несколько файлов одинаковой длины, и даже в этом случае прямое побайтное сравнение скорее всего найдет несоответствия очень быстро.

Я согласен с проверкой длины в первую очередь. Но лучше использовать хэши: шансы получить две одинаковые суммы MD5 для разных файлов крайне малы, и вы могли бы использовать лучшие алгоритмы хеширования. Если у вас большие файлы, контрольная сумма лучше, потому что вы читаете файл только один раз. Предположим, у вас есть три видео по 1 ГБ одинакового размера, с контрольными суммами, которые вы читаете, по 3 ГБ, с побайтным сравнением, которое вы читаете, с 6 ГБ. Также побайтовое сравнение равно O (n²), когда сравнение хэшей может быть линейным. xenoid 6 лет назад 0
Лучше всего никогда не полагаться на контрольную сумму для идентификации файла. Я бы посчитал лучше несколько (разные алгоритмы) хэшей, но в конечном итоге вы действительно проверяете не дубликат, а дублирующую подпись. Поднимите руки, кто хочет объяснить генеральному директору, почему эти важные файлы были удалены случайно. :-) Если нет серьезных ограничений по времени / производительности, которые оправдывают риск потери данных, всегда делайте правильную проверку, чтобы быть уверенным. Тем не менее, обратите внимание, что использование контрольных сумм на всех рисках * не * приводит к удалению некоторых дубликатов, но это всегда более безопасная ставка, чем случайное удаление. StephenG 6 лет назад 0
Хеши работают хорошо. Git основан на хешах, как и целый ряд приложений безопасности (например, сертификат HTTPS вашего банка или веб-сайт вашей компании). Если вы действительно параноик, вы можете дополнить хэш байтовым сравнением, которое будет линейным по времени, так как оно будет каждый раз находить равенство. xenoid 6 лет назад 0
0
Attie

Я бы порекомендовал что-то вроде следующего:

find . -type f \ | xargs md5sum \ | sort -k1,1 \ | uniq -Dw32 

При этом будут перечислены все дублированные файлы в группах файлов с одинаковым хешем MD5.

Остерегайтесь, потому что -w32аргумент to uniqбудет сравнивать только первые 32 символа ... если вы измените длину хеша, вам нужно будет обновить это.


Рассмотрим следующее дерево со следующим содержанием:

./a/1: foo ./a/2: bar ./b/3: hello world ./b/d/5: bar ./c/4: foo 
$ find . -type f \ > | xargs md5sum \ > | sort -k1,1 \ > | uniq -Dw32 c157a79031e1c40f85931829bc5fc552 ./a/2 c157a79031e1c40f85931829bc5fc552 ./b/d/5 d3b07384d113edec49eaa6238ad5ff00 ./a/1 d3b07384d113edec49eaa6238ad5ff00 ./c/4 

Теперь вы можете обрабатывать строки одну за другой ... каждая строка с соответствующим хешем в первых точках файла, который может быть дублирован.

Если вы не слишком обеспокоены тем, какой файл будет удален, то что-то вроде этого работает:

find . -type f \ | xargs md5sum \ | sort -k1,1 \ | uniq -Dw32 \ | while read hash file; do  [ "$" == "$" ] && rm -v "$" prev_hash="$";  done 

Обратите внимание, что MD5 больше не считается безопасным ... поэтому, если вы используете это в системе, где пользователи имеют контроль над файлами, тогда для них вполне возможно спроектировать коллизию - и, таким образом, вы случайно удалите легитимного / целевого объекта файл вместо дедупликации, как вы надеялись. Предпочитаю более сильный хеш, такой как SHA-256 .

Похожие вопросы