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

Я просто использовал Recuva и Photorec для восстановления некоторых данных со случайно отформатированного диска. Естественно, результатом является каждый неповрежденный файл, который когда-либо существовал на диске в течение его срока службы. Это означает десятки тысяч маленьких изображений значков, как PNG, так и JPG, которые я хотел бы удалить - скажем, все, что меньше 100 x 100 пикселей.

Есть решения из там, но все они довольно сложные и даже самые простые полагаться на трубопровод через несколько внешних программ и rmдля фактического удаления. Это не идеально, потому что, когда вы делаете что-то достаточно часто в bash Я всегда предпочитаю однострочный текст, который я могу запомнить и каждый раз вводить в командной строке.

В эпоху гораздо более полноценного GNU find что идет с -delete, неужели нет возможности сделать это полностью или даже в основном внутри find сам?

РЕДАКТИРОВАТЬ: Если find не буду сокращать его, я также был бы рад использовать любой другой инструмент GNU.

1 ответ

Решение

В эпоху гораздо более полноценного GNU find что идет с -delete, неужели нет возможности сделать это полностью или даже в основном внутри find сам?

findне для чтения (мета) данных изображения (сравните "DOTADIW"). Чтобы выполнить произвольный тест, используйте -execв качестве теста ( пример), а затем -delete. Это может быть так:

find . -type f -exec some_program -with -options -that -test -dimensions {} \; -delete

Iff some_program возвращает статус выхода 0 для файла тогда -delete пинает за файл.

Для более сложных тестов вам может понадобиться внутренняя оболочка:

find . -type f -exec sh -c 'shell-code "$1" | with-pipes && con-di-tio-nals -and -such' arbitrary-name {} \; -delete

Iff sh возвращает статус выхода 0 тогда -delete вступит в силу.

Одно большое преимущество: вы можете делать это безопасно, даже если в именах файлов есть символы новой строки, пробелы или специальные символы. Код надежный.

Один большой недостаток: -exec … \; будет работать один some_program на файл. Или один sh, shell-code, with-pipes и con-di-tio-nalsна файл. Создание дополнительного процесса стоит дорого, поэтому этот подход может не сработать.

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

find . -iname "*.jpg" -type f -exec bash -c 'for i; do size=($(identify -format "%w %h" "$i")); (( size[0] < 300 || size[1] < 300 )) && rm -v "$i"; done' remove-files {} +

Запись -exec … + это не тест, который запустил бы -delete. Каждый процесс оболочки обрабатывает несколько файлов и возвращает единый статус выхода, так что это бесполезный тест для одного файла. Вместо, rm условно вызывается из оболочки.

Тем не менее будет один identify на файл и один rmна файл, который необходимо удалить. С другой стороны будет один bashна много файлов. Для хорошей производительности вы должны настоятельно предпочесть встроенные функции оболочки, арифметику оболочки и синтаксис оболочки над внешними исполняемыми файлами. Этот подход по-прежнему обрабатывает имена файлов безопасно и надежно.


Существуют инструменты, с помощью которых можно протестировать множество файлов за один процесс. Пример:

exiftool -q -r -if '$ImageHeight < 100' -if '$ImageWidth < 100' -p '$Directory/$FileName' .

(Это exiftool из libimage-exiftool-perlпакет в Debian. Решение взято из этого ответа.)

Обратите внимание, что эта конкретная команда не ограничивается "PNG и JPG".

Команда выводит такие результаты как find . … -printбыло бы. Затем вы можете подключиться к xargs звонить rm. Общие опасения по поводу путей трубопровода при применении текста, и я не уверен, что можно сделать exiftool вести себя как find . … -print0.

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

Другие вопросы по тегам