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

  • Найти все .php-файлы внутри каталогов с доступными для записи разрешениями
  • Список файлов, содержащих определенное слово в их тексте
  • Как скопировать список файлов и настроить имена файлов назначения на лету?
  • Использование функции zsh в поиске?
  • Выполнение сценария оболочки из командной строки
  • Поиск точек монтирования с помощью команды find?
  • Как удалить файлы, отфильтрованные awk
  • `find` multiple -o -name условие AND! -имя
  • 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

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

    Interesting Posts

    Gnome по умолчанию использует wayland; как я могу вернуться к X11?

    Проблема с псевдонимом Bash

    Насколько надежна (или будет) btrfs отправлять / получать?

    Невозможно получить доступ к содержимому HTTP, но HTTPS и SSH прекрасны

    Поддерживает ли Linux ThinkPad Helix 2?

    сетевая карта инициализируется слишком долго (похоже, проблема с прошивкой)

    eth0 не настроен автоматически

    Отправка команд другому терминалу

    Абсолютно заключить в тюрьму пользователя с минимальными правами доступа к IP, файлу и командам

    Не может обрабатывать диск, потому что «недопустимый токен первичный»

    Программно запускать фоновые задачи на разделенном экране?

    Настройка VLAN через командную строку работает, ifcfg-ethX.Y не делает (CentOS 6.8)

    Где хранится таблица разделов GUID на устройстве?

    Как настроить разные сеансы для разных пользователей?

    zsh автозавершение некоторых частей каталога

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