Intereting Posts
Рекомендуемые ресурсы для работы с сервером только для терминалов? Каков наилучший способ разработки графического интерфейса на серверной машине? {exec} заставляет Conky остановиться Как легко проверить оповещение по электронной почте munin? Присоединиться, заполнив отсутствующие значения ключа Пазл расширения Открытый сертификат OpenSSL с общим именем длиной более 64 байт трафик трафика на github через определенный сетевой интерфейс Сценарий Bash для подсчета типов файлов в пути (включая подпапки) Как установить гостевые дополнения Virtualbox в CentOS только с помощью командной строки CentOS определяет те же дату и часовой пояс для системы и MySQL Есть ли способ сбросить корзину / мусорную корзину из командной строки? Сохранить HTML из буфера обмена как текст разметки подключиться к удаленному серверу через ssh Каков наилучший способ резервного копирования файлов через сеть на компьютерах Linux и Solaris?

Фильтровать файлы, сгенерированные `find`, с помощью обработанного вывода команды` file`

Я пишу быстрый инструмент для проверки содержимого папки node.js node_modules или python virtualenv для собственных зависимостей. В качестве быстрого первого приближения к этому я написал следующую команду.

 find . | xargs file | awk '/C source/ {print $1} /ELF/ {print $1}' 

Я в порядке с ложными срабатываниями, но не ложными негативами (например, файлы, буквально содержащие строку ELF или C source могут быть помечены подозрительными.), Но этот скрипт также потенциально ломается на длинных именах файлов (поскольку xargs будет их разделять) и имена файлов, содержащие пробелы (потому что awk будет разделяться на пробелы) и имена файлов, содержащие новые строки (потому что find использует новые строки для разделения путей).

Есть ли способ фильтровать пути, сгенерированные find , если вы видите, что вывод file {} (возможно, с некоторыми дополнительными параметрами для удаления пути целиком из вывода file ) соответствует определенному регулярному выражению?

Ключевым фактором в достижении find просвещения является:):

бизнес find – это оценка выражений – не поиск файлов. Да, find конечно, находит файлы; но это действительно просто побочный эффект.

–Unix Электроинструменты

Существует альтернативный подход к этому вопросу, о котором стоит знать (как описано в Unix Power Tools, в разделе «Использование -exec для создания пользовательских тестов» ):

 find . -type f -exec sh -c 'file -b "$1" | grep -iqE "^ELF|^C source"' sh {} \; -print 

Стоит знать об этом методе фильтрации, поскольку его можно использовать для многих других вещей, чем просто распечатать имя файла; просто измените оператор -print на любой другой оператор, который вам нравится (в том числе другой -exec оператор) и сделайте то, что вам нравится.


Существует недостаток производительности для этой команды (которая также присутствует в другом ответе ), которая заключается в том, что, поскольку мы используем \; и не + , мы создаем оболочку для каждого отдельного файла. Использование + для одновременного передачи нескольких файлов команде sh и обработки их циклом for дает заметное преимущество в производительности:

 find . -exec sh -c 'for f do file -b "$f" | grep -qE "^ELF|^C source" && printf %s\\n "$f"; done' sh {} + 

Вы можете увидеть сравнение для себя, выполнив обе следующие команды и сравнив вывод time :

 time find . -exec sh -c 'for f do file -b "$f" | grep -qE "^ELF|^C source" && printf %s\\n "$f"; done' sh {} + time find . -exec sh -c 'file -b "$1" | grep -qE "^ELF|^C source" && printf %s\\n "$1"' sh {} \; 

Реальная точка, однако, заключается в следующем:

Никогда не запускайте оболочку for цикла в списке файлов, которые выводятся из find . Вместо этого запустите действие, которое необходимо выполнить для каждого файла непосредственно внутри find , используя оператор -exec или вставьте оболочку for цикла внутри команды find и сделайте это таким образом.

Некоторые дополнительные причины:

  • Почему мой сценарий оболочки задыхается от пробелов или других специальных символов?
  • Почему использование цикла оболочки для обработки текста считается плохой практикой?

Проще всего выполнить небольшой скрипт для каждого файла, который проверяет вывод в кратком режиме file и печатает путь, если выход file соответствует ELF или C source , путь передается как $0 .

 find . -type f -exec sh -c \ 'file -b "$0" | grep -q "^ELF\|^C source" && printf %s\\n "$0"' {} \; 

Это решение имеет следующие преимущества перед оригиналом

-type f отфильтровывает каталоги сразу вместо того, чтобы полагаться на вывод file

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