Re: Поиск и удаление дублирующих файлов
Sergey Stremidlo wrote:
> 05.11.2011 08:13, Нагашибай Жанибек пишет:
>> Какие программы есть на эту тему? Желательно, чтоб можно было
>> посмотреть список файлов-дубляжей и выборочно удалить любой из них.
>>
>>
> Вот моё творение:
Помимо того, что велосипед (fdupes!), несколько замечаний ниже:
> #! /bin/bash
>
> # Алгоритм работы скрипта:
> # 1. Составить список файлов
> # 2. Вычислить все md5 суммы файлов
> # 3. Отсортировать список по md5 суммам
> # 4. Пройтись по списку, сравнивая попарно md5 записанные в
> строках и
> # если текущая совпала с предыдущей то вывести обе, но одну
> пометить file: а другую dup:
> # А чтобы третья и последующая так же не выдавали метки
> file: то можно использовать имя файла в предыдущей строке
> # как флаг, и обнулять его после первого вывода метки file:
> #
> # впоследствии можно скормить файл grep "^dup" и затем rm
> #
> # Создаем файл блокировки find_duplicate.process чтобы
> повторно не запустился поиск
> # одновременно в этом файле находится фраза, описывающая какие
> действия выполняет скрипт.
> # Вот примеры того что бывает в этом файле:
> # 'Построение списка файлов...'
> # '23634 of 3974653'
>
> #
> # fixme: перенаправить stderr в файл
> # такая команда не помогает:
> # 2>$0.errlog
exec 2>$0.errlog
>
> if [ -e $0.process ]
> then
> echo "Already running..."
Я бы не помещал флаг в той же директории, что и скрипт. И сделал бы его per-user.
> exit
> fi
>
> if [ $# -ne 2 ]
> then
> echo "Use: $0 <dir> <out_file>"
> exit
exit 1
> fi
>
> FINDDIR="$1"
> TMPNAME=`tempfile`
>
> echo 'Построение списка файлов...' > $0.process
>
> # составим список только файлов (исключая директории)
>
> find $FINDDIR -type f > $TMPNAME.list
1) "$FINDDIR"
2) использовать $TMPNAME.list и иже с ним - небезопасно.
TMPLIST=`tempfile`
TMPLIST2=`tempfile`
MD5LIST=`tempfile`
MD5SORT=`tempfile`
DUPS=`tempfile`
trap "rm -f $TMPLIST $TMPLIST2 $MD5LIST $MD5SORT $DUPS; exit" 0 INT TERM QUIT
find ... >$TMPLIST
> # отфильтруем не нужные
>
> cat $TMPNAME.list | grep -v "/Trash/" > $TMPNAME.list2
1) useless use of cat: grep -v "/Trash/" $TMPLIST ... > $TMPLIST2
2) можно было бы запихнуть это в условие сразу в find -
find "$FINDDIR" -name Trash -prune -o -type f -print
> mv $TMPNAME.list2 $TMPNAME.list
>
> # определим количество файлов
> # для того чтобы отображать сколько файлов уже обработано
>
> CNT=`grep -c "" $TMPNAME.list`
s/grep -c ""/wc -l/
> # вычислим суммы файлов
> rm -f $TMPNAME.md5
> n=1
> while read FN
> do
> echo "$n of $CNT" > $0.process
> MD5=`md5sum "$FN"`
I'd prefer higher efficiency over UI frills.
tr '\n' '\0' < $TMPLIST | xargs -0r md5sum >$MD5LIST
> echo "$MD5" >> $TMPNAME.md5
> let n=n+1
> done < $TMPNAME.list
> rm $0.process
> rm $TMPNAME.list
>
> MD5PRE=
> FNPRE=
>
> rm -f $TMPNAME.dup
>
> n=1
> sort $TMPNAME.md5 > $TMPNAME.md5.sorted
> rm -f $TMPNAME.md5
> while read LINE
> do
> MD5=${LINE%% *}
> FN=${LINE#* }
while read MD5 FN
...
> if [ "$MD5" = "$MD5PRE" ]
> then
> # если мд5 текущего и предыдущего совпали
> # но имя предыдущего файла не пустое, значит
> выводим две строки
> # и опустошаем имя предыдущего файла чтобы по
> этому признаку определить
> # что нужно выводить одну строку а не две
> if [ "$FNPRE" != "" ]
if [ -n "$FNPRE" ]
> then
... но я бы для поиска дупликатов заюзал uniq -w32 -D :-)
> echo "file: $FNPRE" >> $TMPNAME.dup
> echo " dup: $FN" >> $TMPNAME.dup
> FNPRE=
> else
> echo " dup: $FN" >> $TMPNAME.dup
> fi
> let n=n+1
> else
> MD5PRE=$MD5
> FNPRE=$FN
> fi
> done < $TMPNAME.md5.sorted
> rm -f $TMPNAME.md5.sorted
> mv $TMPNAME.dup "$2"
Ах да, коллизии для md5 не новость, давно пора переходить с md5 на более другой
хеш; учитывая, что sha1 уже тоже дисквалифицирован, можно сразу на sha256 (или
sha512).
Reply to: