Unix find: поиск исполняемых файлов

Какой тип параметра / флага я могу использовать с Unix find команда, чтобы я искал исполняемые файлы?

9 ответов

Решение

На GNU версии find вы можете использовать -executable:

find . -type f -executable -print

Для BSD-версий find вы можете использовать -perm с + и восьмеричная маска:

find . -type f -perm +111 -print

В этом контексте "+" означает "любой из этих битов установлен", а 111 - биты исполнения.

Обратите внимание, что это не идентично -executable Предикат в GNU найти. Особенно, -executable проверяет, что файл может быть выполнен текущим пользователем, в то время как -perm +111 просто проверяет, установлены ли какие-либо разрешения на выполнение.

Старые версии GNU find также поддерживают -perm +111 синтаксис, но с 4.5.12 этот синтаксис больше не поддерживается. Вместо этого вы можете использовать -perm /111 чтобы получить это поведение.

Наконечник шляпы @ gniourf_gniourf для gniourf_gniourf фундаментального заблуждения.

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

Поиск исполняемых файлов может ссылаться на два разных варианта использования:

  • ориентированный на пользователя: поиск файлов, которые могут быть выполнены текущим пользователем.
  • file-centric: поиск файлов с установленными (одним или несколькими) исполняемыми битами разрешений.

Обратите внимание, что в любом сценарии может иметь смысл использовать find -L ... вместо просто find ... чтобы также найти символические ссылки на исполняемые файлы.

Обратите внимание, что простейший файлово-ориентированный случай - поиск исполняемых файлов с битом разрешений на исполняемый файл, установленным для ВСЕХ трех участников безопасности (пользователь, группа, другое) - обычно, но не обязательно, дает те же результаты, что и сценарий, ориентированный на пользователя, - и это важно понимать разницу.

Ориентированный на пользователя (-executable)

  • Принятый ответ похвально рекомендует -executable IF IF GNU find доступен.

    • GNU find поставляется с большинством дистрибутивов Linux
      • В отличие от этого, платформы на базе BSD, включая macOS, поставляются с BSD find, который является менее мощным.
    • Как требует сценарий, -executable соответствует только файлам, которые может выполнить текущий пользователь (есть крайние варианты. [1]).
  • BSD find альтернатива предложенного принятого ответа ( -perm +111 ) отвечает на другой файлово-ориентированный вопрос (как говорится в самом ответе).

    • Используя только -perm ответить на вопрос, ориентированный на пользователя, невозможно, потому что необходимо связать личность пользователя и группы в файле с текущим пользователем, тогда как -perm можно только проверить права доступа к файлу.
      Использование только POSIX find особенности, вопрос не может быть дан ответ без привлечения внешних утилит.
    • Таким образом, лучший -perm может сделать (само по себе) является приближением -executable, Возможно, более близкое приближение, чем -perm +111 является -perm -111, чтобы найти файлы с установленным исполняемым битом для ВСЕХ участников безопасности (пользователь, группа, другое) - это выглядит как типичный сценарий реального мира. В качестве бонуса, он также оказывается POSIX-совместимым (используйте find -L чтобы включить символические ссылки, см. ниже для объяснения):

      find . -type f -perm -111  # or: find . -type f -perm -a=x
      
  • Ответ gniourf_gniourf обеспечивает истинный, переносимый эквивалент -executable, с помощью -exec test -x {} \; Хотя и за счет производительности.

    • Объединяя -exec test -x {} \; с -perm +111 (то есть файлы с хотя бы одним установленным исполняемым битом) могут повысить производительность в этом exec не нужно вызывать для каждого файла (ниже используется POSIX-совместимый эквивалент BSD find -perm +111 / GNU найти -perm /111; см. ниже ниже для объяснения):

      find . -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \) -exec test -x {} \; -print
      

Файлоцентричный (-perm)

  • Чтобы ответить на вопросы, связанные с файлами, достаточно использовать POSIX-совместимый -perm основной (известный как тест в GNU найти терминологию).
    • -perm позволяет проверять любые права доступа к файлам, а не только исполняемость.
    • Разрешения указываются в восьмеричном или символическом режимах. Восьмеричные моды - это восьмеричные числа (например, 111), тогда как символические режимы - это строки (например, a=x).
    • Символьные режимы идентифицируют участников безопасности как u (Пользователь), g (группа) и o (другое) или a сослаться на все три. Разрешения выражаются как x например, для исполняемого файла и назначается принципалам с помощью операторов =, + а также -; для полного обсуждения, включая восьмеричные режимы, см. спецификацию POSIX для chmod утилита
    • В контексте find:
      • Префикс режима с - (например, -ug=x) означает: сопоставлять файлы, которые имеют все указанные разрешения (но соответствующие файлы могут иметь дополнительные разрешения).
      • Без префикса (например, 755) означает: сопоставлять файлы с полным набором разрешений.
      • Предостережение: И GNU-поиск, и BSD-поиск реализуют дополнительный нестандартный префикс с логикой "любой из указанных битов разрешения", но делают это с несовместимым синтаксисом:
        • BSD найти: +
        • GNU найти: / [2]
      • Поэтому избегайте этих расширений, если ваш код должен быть переносимым.
  • Приведенные ниже примеры демонстрируют переносимые ответы на различные файловые вопросы.

Примеры файлово-ориентированных команд

Замечания:

  • Следующие примеры являются POSIX-совместимыми, что означает, что они должны работать в любой POSIX-совместимой реализации, включая GNU find и BSD find; в частности, для этого необходимо:
    • НЕ использовать префиксы нестандартного режима + или же /,
    • Использование форм POSIX основных логических операторов:
      • ! для НЕ (GNU найти и BSD найти также позволяют -not); Обратите внимание, что \! используется в примерах для защиты ! из расширений истории оболочки
      • -a для AND (GNU find и BSD find также позволяют -and)
      • -o для ИЛИ (GNU найти и BSD найти также позволяют -or)
  • В примерах используются символические режимы, потому что их легче читать и запоминать.
    • С префиксом режима -, = а также + операторы могут использоваться взаимозаменяемо (например, -u=x эквивалентно -u+x - если вы не подадите заявку -x позже, но в этом нет никакого смысла).
    • использование , включить частичные режимы; И логика подразумевается; например, -u=x,g=x означает, что должен быть установлен как пользовательский, так и исполняемый бит группы.
    • Сами по себе режимы не могут выражать отрицательное сопоставление в смысле "сопоставлять, только если этот бит НЕ установлен"; Вы должны использовать отдельный -perm выражение с НЕ первичным, !,
  • Обратите внимание, что найти праймериз (например, -print, или же -perm; также известные как действия и тесты в GNU find), неявно объединяются с -a (логическое И), и это -o и, возможно, скобки (экранированные как \( а также \) для оболочки) необходимы для реализации логики ИЛИ.
  • find -L ... вместо просто find ... используется для того, чтобы также сопоставить символические ссылки с исполняемыми файлами
    • -L инструктирует find для оценки целей символических ссылок вместо самих символических ссылок; следовательно, без -L, -type f будет игнорировать символические ссылки в целом.
# Match files that have ALL executable bits set - for ALL 3 security
# principals (u (user), g (group), o (others)) and are therefore executable
# by *anyone*.
# This is the typical case, and applies to executables in _system_ locations
# (e.g., /bin) and user-installed executables in _shared_ locations
# (e.g., /usr/local/bin), for instance. 
find -L . -type f -perm -a=x  # -a=x is the same as -ugo=x

# The POSIX-compliant equivalent of `-perm +111` from the accepted answer:
# Match files that have ANY executable bit set.
# Note the need to group the permission tests using parentheses.
find -L . -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \)

# A somewhat contrived example to demonstrate the use of a multi-principial
# mode (comma-separated clauses) and negation:
# Match files that have _both_ the user and group executable bit set, while
# also _not_ having the other executable bit set.
find -L . -type f -perm -u=x,g=x  \! -perm -o=x

[1] Описание -executable от man find по состоянию на GNU найти 4.4.2:

Соответствует исполняемым файлам и каталогам, доступным для поиска (в смысле разрешения имен файлов). При этом учитываются списки контроля доступа и другие артефакты разрешений, которые тест -perm игнорирует. Этот тест использует системный вызов access(2) и поэтому может быть одурачен серверами NFS, которые выполняют сопоставление UID (или сжатие корня), так как многие системы реализуют access(2) в ядре клиента и поэтому не могут использовать информация отображения UID, хранящаяся на сервере. Поскольку этот тест основан только на результате системного вызова access(2), нет никакой гарантии, что файл, для которого этот тест будет успешно выполнен, действительно может быть выполнен.

[2] GNU находит версии старше 4.5.12, также разрешенный префикс + , но это было сначала устарело и в конечном итоге удалено, потому что объединение + с символическими режимами дает, скорее всего, неожиданные результаты из-за того, что интерпретируется как точная маска разрешений. Если вы (a) используете версию до 4.5.12 и (b) ограничиваетесь только восьмеричными режимами, вы можете избежать использования + и с GNU find, и с BSD find, но это не очень хорошая идея.

Чтобы иметь еще одну возможность1 найти файлы, которые исполняются текущим пользователем:

find . -type f -exec test -x {} \; -print

(здесь есть тестовая команда, найденная в PATH, очень вероятно, /usr/bin/testне встроенный).


1 Используйте это только если -executable флаг find не доступен! это немного отличается от -perm +111 решение.

Вы можете использовать -executable тестовый флаг:

-executable
              Matches files which are executable  and  directories  which  are
              searchable  (in  a file name resolution sense).
find . -executable -type f

на самом деле не гарантирует, что файл является исполняемым, он найдет файлы с установленным битом выполнения. Если вы делаете

chmod a+x image.jpg

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

Я обычно работаю над этим вопросом:

find . -type f -executable -exec file {} \; | grep -wE "executable|shared object|ELF|script|a\.out|ASCII text"

Если вы хотите, чтобы find действительно печатала купольную информацию об исполняемых файлах, вы можете сделать что-то вроде этого:

find . -type f -executable -printf "%i.%D %s %m %U %G %C@ %p" 2>/dev/null |while read LINE
do
  NAME=$(awk '{print $NF}' <<< $LINE)
  file -b $NAME |grep -qEw "executable|shared object|ELF|script|a\.out|ASCII text" && echo $LINE
done

В приведенном выше примере полный путь к файлу находится в последнем поле и должен отражать, где вы ищете его с помощью awk "NAME=$(awk '{print $NF}' <<< $LINE)", если имя файла было где-то еще в найти выходную строку вам нужно заменить "NF" на правильную числовую позицию. Если ваш разделитель не является пробелом, вы также должны указать awk, какой у вас разделитель.

Это сработало для меня и думал поделиться...

find ./ -type f -name "*" -not -name "*.o" -exec sh -c '
    case "$(head -n 1 "$1")" in
      ?ELF*) exit 0;;
      MZ*) exit 0;;
      #!*/ocamlrun*)exit0;;
    esac
exit 1
' sh {} \; -print

Поэтому, если вы действительно хотите найти исполняемые типы файлов (например, скрипты, двоичные файлы ELF и т. Д. И т. Д.), А не просто файлы с разрешением на выполнение, то вы, вероятно, захотите сделать что-то более похожее (где текущий каталог. Может быть заменен любым каталог, который вы хотите):

 gfind . -type f -exec bash -c '[[ $(file -b "'{}'") == *" executable "* ]] ' \; -print

Или для тех из вас, кто не использует macports (пользователи linux) или иным образом установил gnu find так, как вам нужно:

 find . -type f -exec bash -c '[[ $(file -b "'{}'") == *" executable "* ]] ' \; -print

Хотя, если вы работаете в OS X, он поставляется с небольшой утилитой, скрытой где-то под названием is_exec, которая в основном связывает этот маленький тест для вас, чтобы вы могли сократить командную строку, если найдете ее. Но этот способ является более гибким, поскольку вы можете легко заменить тест == тестом =~ и использовать его для проверки более сложных свойств, таких как исполняемые текстовые файлы или любую другую информацию, которую возвращает ваша файловая команда.


Точные правила цитирования здесь довольно непрозрачны, поэтому я просто заканчиваю работу над ними методом проб и ошибок, но я бы хотел услышать правильное объяснение.

Ну, простой ответ будет: "ваши исполняемые файлы находятся в каталогах, содержащихся в вашей переменной PATH", но это на самом деле не найдет ваши исполняемые файлы и может пропустить много исполняемых файлов в любом случае.

Я не знаю много о Mac, но я думаю, что "mdfind 'kMDItemContentType=public.unix-executetable'" может пропустить такие вещи, как интерпретируемые скрипты

Если для вас нормально найти файлы с установленными исполняемыми битами (независимо от того, являются ли они на самом деле исполняемыми), тогда это можно сделать

find . -type f -perm +111 -print

там, где поддерживается опция "-executable", дополнительный фильтр будет проверять acl и другие артефакты разрешений, но технически не сильно отличается от "-pemr +111".

Возможно, в будущем find будет поддерживать "-magic " и позволит вам явно искать файлы с определенным магическим идентификатором... но тогда вам нужно будет указать, чтобы все исполняемые форматы идентифицировали магический идентификатор.

Я не знаю о технически правильном простом выходе на Unix.

Это так смешно, что это не супер-легко... не говоря уже о невозможном. Руки вверх, я откладываю на Apple/Spotlight...

mdfind 'kMDItemContentType=public.unix-executable'

По крайней мере, это работает!

У меня была та же проблема, и ответ был в исходном коде dmenu: утилита stest, созданная для этой цели. Вы можете скомпилировать файлы 'stest.c' и 'arg.h', и это должно работать. Есть справочная страница для использования, которую я поместил туда для удобства:

STEST(1)         General Commands Manual         STEST(1)

NAME
       stest - filter a list of files by properties

SYNOPSIS
       stest  [-abcdefghlpqrsuwx]  [-n  file]  [-o  file]
       [file...]

DESCRIPTION
       stest takes a list of files  and  filters  by  the
       files'  properties,  analogous  to test(1).  Files
       which pass all tests are printed to stdout. If  no
       files are given, stest reads files from stdin.

OPTIONS
       -a     Test hidden files.

       -b     Test that files are block specials.

       -c     Test that files are character specials.

       -d     Test that files are directories.

       -e     Test that files exist.

       -f     Test that files are regular files.

       -g     Test  that  files  have  their set-group-ID
              flag set.

       -h     Test that files are symbolic links.

       -l     Test the contents of a directory  given  as
              an argument.

       -n file
              Test that files are newer than file.

       -o file
              Test that files are older than file.

       -p     Test that files are named pipes.

       -q     No  files are printed, only the exit status
              is returned.

       -r     Test that files are readable.

       -s     Test that files are not empty.

       -u     Test that files have their set-user-ID flag
              set.

       -v     Invert  the  sense  of  tests, only failing
              files pass.

       -w     Test that files are writable.

       -x     Test that files are executable.

EXIT STATUS
       0      At least one file passed all tests.

       1      No files passed all tests.

       2      An error occurred.

SEE ALSO
       dmenu(1), test(1)

                        dmenu-4.6                STEST(1)
Другие вопросы по тегам