[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: