2017-01-01 2 views
2

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

Сейчас у меня есть код:

#!/bin/bash 

directory="~/Desktop/Test/*" 
for file in ${directory}; 
do 
    for filex in ${directory}: 
    do 
     if [ $(diff {$file} {$filex}) == 0 ] 
     then 
      mv ${filex} ~/Desktop 
      break 
     fi 
    done 
done 

и получить код выхода:

diff: {~/Desktop/Test/*}: No such file or directory 
diff: {~/Desktop/Test/*:}: No such file or directory 
File_compare: line 8: [: ==: unary operator expected 

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

Кроме того, почему кажется, что существуют разные способы вызова переменных? Я видел примеры, которые используют ${file}, "$file", and "${file}".

+0

Попробуйте назначить полный путь. 'directory ="/home/someuser/Desktop/Test/* "' Альтернативно, не используйте кавычки. 'directory = ~/Desktop/Test/*' Кажется, что цитаты вызывают проблемы с расширением тильды. – Guest

+0

Я не могу проверить это прямо сейчас, но я думаю, что попробовал это и получил те же ошибки. – Astrum

ответ

5

Вы имеете {} в неправильных местах:

if [ $(diff {$file} {$filex}) == 0 ] 

Они должны быть на:

if [ $(diff ${file} ${filex}) == 0 ] 

(хотя брекеты в настоящее время не являются обязательными), но вы должны позволить пробелов в именах файлов:

if [ $(diff "${file}" "${filex}") == 0 ] 

Теперь он просто не работает должным образом, потому что, когда diff не обнаруживает различий, он не генерирует выход (и вы получаете ошибки, потому что оператор == ничего не ожидает от его левой стороны). Можно вроде это исправить, дважды указав значение из $(…) (if [ "$(diff …)" == "" ]), но вы должны просто и непосредственно проверить статус выхода diff:

if diff "${file}" "${filex}" 
then : no difference 
else : there is a difference 
fi 

и, возможно, для сравнения изображения, которые вы должны использовать cmp (в бесшумный режим), а не diff:

if cmp -s "$file" "$filex" 
then : no difference 
else : there is a difference 
fi 
+0

Я дам это шоу, когда смогу. Можете ли вы просто объяснить, почему у вас нет «никакой разницы»? Я не понимаю, как это означает «нет вывода». – Astrum

+0

Я имею в виду, что 'if diff ...' проверяет статус выхода команды 'diff', а' diff' возвращает 0 (успех), если эти два файла были идентичны и не равны нулю (отказ), если файлы были разными (или один не был найден, или ...). Поэтому тест 'if' выполняет код' then', когда файлы одинаковы (или между ними нет разницы) или код 'else', когда файлы отличаются друг от друга. Команда ':' - это встроенная оболочка, которая вычисляет свои аргументы и затем преуспевает - в этом контексте это не-операционная система, которую вы можете заменить кодом, который вы хотите исполнить, те же. И т. Д. –

+0

Команда 'diff' будет печатать отличия от стандартного вывода, если есть различия между файлами. Вы можете перенаправить такой вывод в '/ dev/null', если вы не хотите его видеть. OTOH, используя 'cmp -s', уже имеет дело с этим, так как не генерирует никакого вывода. –

1

Вы можете использовать diff "$file" "$filex" &>/dev/null и получить последний результат команды с $?:

#!/bin/bash 

SEARCH_DIR="." 
DEST_DIR="./result" 

mkdir -p "$DEST_DIR" 

directory="." 

ls $directory | while read file; 
do 
    ls $directory | while read filex; 
    do 
     if [ ! -d "$filex" ] && [ ! -d "$file" ] && [ "$filex" != "$file" ]; 
     then 

      diff "$file" "$filex" &>/dev/null 

      if [ "$?" == 0 ]; 
      then 
       echo "$filex is a duplicate. Copying to $DEST_DIR" 
       mv "$filex" "$DEST_DIR" 
      fi 
     fi 
    done 
done 

Обратите внимание, что вы можете также использовать fslint или fdupes утилиты для поиска дубликатов

2

Если вы просто интересно знать, если два файла различаются, cmp является лучшим вариантом.Его преимущество:

  1. Она работает для текста, а также бинарных файлов, в отличие от diff, который только текстовых файлов

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

Таким образом, ваш код может быть записан в виде:

if ! cmp -s "$file" "$filex"; then 
    # files differ... 
    mv "$filex" ~/Desktop 

    # any other logic here 
fi 

Надеюсь, это поможет. Я не понимал, что вы пытаетесь сделать со своими циклами, и, следовательно, не написал полный код.

+0

Я пытаюсь взять каждый 'файл' в каталог и сравнить его со всеми остальными файлами по строке, удаляя дубликаты по мере их появления. Использование кода теперь не работает; он говорит, что все является дубликатом.Здесь: 'для файла в" $ {directory} "/ *; do \t для filex в "$ {directory}"/*; сделать \t \t если CMP -s "$ файла" "$ FileX" \t \t затем \t \t \t: \t \t еще \t \t \t мв -i "$ FileX" ~/Desktop \t \t \t эхо «$ filex " \t \t fi \t done done' – Astrum

+0

Возможно, вы не должны сравнивать файл с самим собой. – codeforester

+0

О, я вижу. Он сравнивает первый файл с собой каждый раз ... что усложняет ситуацию. Есть ли простой способ избежать этого? – Astrum

4

В дополнение к проблемам Джонатан Леффлера отметил:

directory="~/Desktop/Test/*" 
for file in ${directory}; 

~ и * не будут расширены в двойные кавычки; * будет расширяться, когда вы используете переменную без кавычек, но так как ~ не будет, она ищет файлы под каталогом, фактически названной «~» (не вашего домашнего каталога), он не найдет совпадений. Кроме того, как указал Джонатан, использование переменных (например, ${directory}) без двойных кавычек приведет к проблемам с именами файлов, которые содержат пробелы или некоторые другие метасимволы. Лучший способ сделать это, чтобы не поставить подстановочные в переменной, используйте его, когда вы ссылаетесь на переменную, с переменной в двойных кавычках и * за их пределами:

directory=~/"Desktop/Test" 
for file in "${directory}"/*; 

О, и другое примечание: при использовании mv в скрипте рекомендуется использовать mv -i, чтобы избежать случайного перезаписи другого файла с тем же именем.

И: используйте shellcheck.net, чтобы проверить работоспособность вашего кода и указать общие ошибки.

Смежные вопросы