Фильтровать файлы, сгенерированные `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 ) соответствует определенному регулярному выражению?

  • Найти файл, имя которого содержит заданные подстроки одновременно
  • Применение команд chmod и chown динамически к выводу команды find
  • Разделить имя файла и путь внутри опции -exec команды find
  • find: чернослив не игнорирует указанный путь
  • bash - могу ли я найти: -exec this && that?
  • Как выполнить встроенную команду оболочки с помощью find?
  • Выполнение сценария оболочки из командной строки
  • поиск и подглаживание (и подстановочные знаки)
  • 2 Solutions collect form web for “Фильтровать файлы, сгенерированные `find`, с помощью обработанного вывода команды` 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

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

    Linux и Unix - лучшая ОС в мире.