У меня есть каталог с несколькими файлами IMG, и некоторые из них идентичны, но все они имеют разные имена. Мне нужно удалить дубликаты, но без внешних инструментов только с помощью bash
скрипта. Я новичок в Linux. Я пытался использовать вложенный цикл для сравнения md5
сумм и в зависимости от результата удаления, но что-то не так с синтаксисом, и это не работает. любая помощь?
что я пробовал это ...
for i in directory_path; do
sum1='find $i -type f -iname "*.jpg" -exec md5sum '{}' \;'
for j in directory_path; do
sum2='find $j -type f -iname "*.jpg" -exec md5sum '{}' \;'
if test $sum1=$sum2 ; then rm $j ; fi
done
done
Я получил: test: too many arguments
bash
shell-script
linuxbegin
источник
источник
Ответы:
В вашем скрипте довольно много проблем.
Во-первых, чтобы присвоить результат команды переменной, необходимо заключить ее в backtics (
`command`
) или, предпочтительно, в$(command)
. У вас есть это в одинарных кавычках ('command'
), которые вместо назначения результата вашей команды вашей переменной, назначают саму команду в виде строки. Таким образом, вашtest
на самом деле:Следующая проблема заключается в том, что команда
md5sum
возвращает больше, чем просто хэш:Вы хотите сравнить только первое поле, поэтому вы должны проанализировать
md5sum
вывод, передав его через команду, которая печатает только первое поле:или
Кроме того,
find
команда будет возвращать много совпадений, а не только одно, и каждое из этих совпадений будет дублироваться вторымfind
. Это означает, что в какой-то момент вы будете сравнивать один и тот же файл с самим собой, md5sum будет идентичен, и вы в конечном итоге удалите все ваши файлы (я запустил это на тестовой директории, содержащейa.jpg
иb.jpg
):Вы не хотите запускаться,
for i in directory_path
если вы не передаете массив каталогов. Если все эти файлы находятся в одном каталоге, вы хотите запуститьfor i in $(find directory_path -iname "*.jpg"
), чтобы просмотреть все файлы.Это плохая идея использовать
for
циклы с выводом find. Вы должны использоватьwhile
петли или сглаживание :или, если все ваши файлы находятся в одном каталоге:
В зависимости от вашей оболочки и установленных вами параметров, вы можете использовать глобирование даже для файлов в подкаталогах, но давайте не будем вдаваться в подробности.
Наконец, вы также должны заключить в кавычки ваши переменные, иначе пути к каталогам с пробелами сломают ваш скрипт.
Имена файлов могут содержать пробелы, новые строки, обратную косую черту и другие странные символы, чтобы правильно обрабатывать их в
while
цикле, вам потребуется добавить еще несколько параметров. То, что вы хотите написать, это что-то вроде:Еще более простой способ будет:
Лучшая версия, которая может иметь дело с пробелами в именах файлов:
Этот маленький Perl-скрипт будет проходить через результаты
find
команды (т.е. md5sum и имя файла).-a
Вариант дляperl
расколов входных линий пробельных и сохраняет их вF
массиве, так$F[0]
будет md5sum и$F[1]
имя файла. Сумма md5 сохраняется в хэше,k
и скрипт проверяет, был ли хэш уже просмотрен (if $k{$F[0]}>1
), и удаляет файл, если он имеет (system("rm $F[1]")
).Хотя это будет работать, это будет очень медленно для больших коллекций изображений, и вы не сможете выбрать, какие файлы сохранить. Есть много программ, которые обрабатывают это более элегантным способом, включая:
fdupes
fslint
источник
unlink
вместоsystem
звонка.$F[1]
. Исправлено с помощью кусочков массива. Что касается unlink (), я знаю, но хотел свести к минимуму perlisms, и системный вызов легче понять, если вы не знаете Perl.Существует отличная программа,
fdupes
которая упрощает весь процесс и предлагает пользователю удалить дубликаты. Я думаю, что стоит проверить:По сути, мне было предложено сохранить файл , я набрал 1 , а второй удалил.
Другие интересные варианты:
Из вашего примера вы, вероятно, хотите запустить его как:
Смотрите
man fdupes
для всех доступных вариантов.источник