найдите и удалите дубликаты в каталоге

не можете Вы получать идентификатор процесса и общаться с ним с USR1,

$pgrep -l '^ipchecker.sh$'

который печатает PID Вашего сценария, затем используйте его для

$ kill -USR1 PID

Я понимаю, что USR1 является "определяемым пользователем" сигналом, означая, что, кто бы ни создал программу, может использовать его, чтобы означать, что "закрытие" или "выводит Ваши журналы", или "печатают нечто тысячу раз" или что бы то ни было.

12
29.11.2013, 10:38
2 ответа

В Вашем сценарии существует довольно много проблем.

  • Во-первых, для присвоения результата команды к переменной, необходимо включить его любой в обратные галочки (`command`) или, предпочтительно, $(command). У Вас есть он в одинарных кавычках ('command') который вместо того, чтобы присвоить результат Вашей команды к Вашей переменной, назначает самой команде строкой. Поэтому Ваш test на самом деле:

    $ echo "test $sum1=$sum2"
    test find $i -type f -iname "*.jpg" -exec md5sum {} \;=find $j -type f -iname "*.jpg" -exec md5sum {} \;
    
  • Следующий выпуск то, что команда md5sum возвраты больше, чем просто хеш:

    $ md5sum /etc/fstab
    46f065563c9e88143fa6fb4d3e42a252  /etc/fstab
    

    Вы только хотите сравнить первое поле, таким образом, необходимо проанализировать md5sum произведенный путем передачи его посредством команды, которая только печатает первое поле:

    find $i -type f -iname "*.png" -exec md5sum '{}' \; | cut -f 1 -d ' '
    

    или

    find $i -type f -iname "*.png" -exec md5sum '{}' \; | awk '{print $1}' 
    
  • Кроме того, find команда возвратит много соответствий, не всего один, и каждое из тех соответствий будет дублировано вторым find. Это означает в какой-то момент сравнение того же файла с собой md5sum будет идентичен, и Вы закончите тем, что удалили все свои файлы (я выполнил это на тестовом dir, содержащем a.jpg и b.jpg):

    for i in $(find . -iname "*.jpg"); do
      for j in $(find . -iname "*.jpg"); do
         echo "i is: $i and j is: $j"
      done
    done   
    i is: ./a.jpg and j is: ./a.jpg   ## BAD, will delete a.jpg
    i is: ./a.jpg and j is: ./b.jpg
    i is: ./b.jpg and j is: ./a.jpg
    i is: ./b.jpg and j is: ./b.jpg   ## BAD will delete b.jpg
    
  • Вы не хотите работать for i in directory_path если Вы не передаете массив каталогов. Если все эти файлы находятся в том же каталоге, Вы хотите работать for i in $(find directory_path -iname "*.jpg") пройти все файлы.

  • Это - плохая идея использовать for циклы с выводом находки. Необходимо использовать while циклы или globbing:

    find . -iname "*.jpg" | while read i; do [...] ; done
    

    или, если все Ваше ре файлов в том же каталоге:

    for i in *jpg; do [...]; done
    

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

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

Имена файлов могут содержать пробелы, новые строки, обратные косые черты и другие странные символы, для контакта с теми, которые правильно в a while цикл необходимо будет добавить еще некоторые опции. То, что Вы хотите записать, является чем-то как:

find dir_path -type f -iname "*.jpg" -print0 | while IFS= read -r -d '' i; do
  find dir_path -type f -iname "*.jpg" -print0 | while IFS= read -r -d '' j; do
    if [ "$i" != "$j" ]
    then
      sum1=$(md5sum "$i" | cut -f 1 -d ' ' )
      sum2=$(md5sum "$j" | cut -f 1 -d ' ' )
      [ "$sum1" = "$sum2" ] && rm "$j"
    fi
  done
done

Еще более простой путь был бы:

find directory_path -name "*.jpg" -exec md5sum '{}' + | 
 perl -ane '$k{$F[0]}++; system("rm $F[1]") if $k{$F[0]}>1'

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

find directory_path -name "*.jpg" -exec md5sum '{}' + | 
 perl -ane '$k{$F[0]}++; system("rm \"@F[1 .. $#F]\"") if $k{$F[0]}>1'

Этот небольшой сценарий Perl пробежит результаты find команда (т.е. md5sum и имя файла). -a опция для perl разделения вводят строки в пробеле, и сохраняет их в F массив, таким образом, $F[0] будет md5sum и $F[1] имя файла. md5sum сохраняется в хеше k и сценарий проверяет, был ли хеш уже замечен (if $k{$F[0]}>1) и удаляет файл, если он имеет (system("rm $F[1]")).


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

28
27.01.2020, 19:54
  • 1
    +1 для отрывка Perl. Действительно изящный! Можно также использовать собственный Perl unlink вместо того, чтобы делать a system звонить. –  Joseph R. 24.11.2013, 20:05
  • 2
    @JosephR. спасибо :). Имел ошибку, хотя, она перестанет работать для имен файлов с пробелами с тех пор, только первые символы имени до первого пространства были бы в $F[1]. Зафиксированный это с помощью частей массива. Что касается удаляют связь (), я знаю, но требуемый для сведения к минимуму perlisms и системного вызова легче понять, не знаете ли Вы Perl. –  terdon♦ 24.11.2013, 20:11

Существует изящная названная программа fdupes это упрощает целый процесс и предлагает пользователю удаление дубликатов. Я думаю, что это стоит проверить:

$ fdupes --delete DIRECTORY_WITH_DUPLICATES
[1] DIRECTORY_WITH_DUPLICATES/package-0.1-linux.tar.gz        
[2] DIRECTORY_WITH_DUPLICATES/package-0.1-linux.tar.gz.1

Set 1 of 1, preserve files [1 - 2, all]: 1

   [+] DIRECTORY_WITH_DUPLICATES/package-0.1-linux.tar.gz
   [-] DIRECTORY_WITH_DUPLICATES/package-0.1-linux.tar.gz.1

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

Другие интересные опции:

-r --recurse
    for every directory given follow subdirectories encountered within

-N --noprompt
    when used together with --delete, preserve the first file in each set of duplicates and delete the others without prompting the user

От Вашего примера Вы, вероятно, хотите выполнить его как:

fdupes --recurse --delete --noprompt DIRECTORY_WITH_DUPLICATES

Посмотрите man fdupes для всех доступных опций.

13
27.01.2020, 19:54

Теги

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