Поиск исполняемых файлов с помощью команды find

114

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

а на самом деле
источник
введите "найти человека". Я думаю, что вам нужен "-executable".
sje397
3
find -executable... но это не гарантирует, что каждый указанный файл действительно будет выполнен
Уильям
1
Не все реализации findодинаковы. Вариант, рекомендованный @ sje397 и @William, может быть недоступен. Лучше использовать принятое решение, показанное ниже.
LS
Мне не нравятся все представленные ниже предложения, основанные на разрешениях на доступ к файлам. Аргументация: для моей операционной системы GNU (Ubuntu) можно установить флаг «x» (исполняемый), например, для текстового файла ASCII. Никакая мимика не помешала успешному завершению этой операции. Требуется небольшая ошибка / ошибка для нескольких файлов без намерения, чтобы установить флаг x. Поэтому решения gniourf_gniourf - мои любимые. Однако у него есть тот недостаток, что для кросс-скомпилированных исполняемых файлов требуется эмулятор или целевое устройство.
Na13-c

Ответы:

175

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

find . -type f -executable -print

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

find . -type f -perm +111 -print

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

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

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

Лоуренс Гонсалвес
источник
Ошибка find: invalid mode ‘+111’на findutils 4.5.11 4.fc20.
sourcejedi
1
@sourcejedi Спасибо. На самом деле я говорил только о версиях find, отличных от GNU (в частности, BSD), но более старые версии GNU find действительно поддерживали этот синтаксис. В более новых версиях вам придется использовать /вместо +. См. Обновленный ответ для получения более подробной информации.
Laurence Gonsalves
В самом деле, я неправильно понял ваш ответ. Простите, что усложняю :).
sourcejedi
Если символические ссылки на исполняемые файлы также должны быть найдены, включает в себя -Lвариант: find -L ....
mklement0
Мне потребовалось время, чтобы понять значение «не идентично предикату -executable» и «просто проверяет, установлены ли какие-либо разрешения на выполнение»: это означает, что это -perm +111может привести к ложным срабатываниям , то есть к файлам, которые текущий пользователь не может выполнить. Там нет никакого способа , чтобы эмулировать -executableпутем тестирования разрешений в одиночку, потому что нужно, чтобы связать в файл пользователей и групп идентичность с текущим пользователем .
mklement0
35

Совет от @ gniourf_gniourf за прояснение фундаментального заблуждения.

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

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

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

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

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

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

  • Общепринятый ответ похвально рекомендует -executable, ЕСЛИ GNU find доступен.

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

    • Использование только -permдля ответа на пользователь заточенный вопроса является невозможным , потому что нужно, чтобы связать в файл пользователей и групп идентичность с текущим пользователем , в то время как -permможно только проверить в файл разрешение.
      Используя только функции POSIXfind , на вопрос нельзя ответить без привлечения внешних утилит.
    • Таким образом, лучшие -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 -perm +111/ GNU find -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 find, так и BSD find реализуют дополнительный нестандартный префикс с логикой набора битов-ЛЮБОГО-из-указанного-разрешения , но делают это с несовместимым синтаксисом :
        • BSD находит: +
        • Находка GNU: / [2]
      • Поэтому избегайте этих расширений, если ваш код должен быть переносимым .
  • Приведенные ниже примеры демонстрируют переносимые ответы на различные вопросы, связанные с файлами.

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

Примечание:

  • Следующие примеры являются POSIX-совместимыми , то есть они должны работать в любой POSIX-совместимой реализации, включая GNU find и BSD find; в частности, это требует:
    • НЕ использовать нестандартные префиксы режима +или /.
    • Использование форм POSIX первичных логических операторов :
      • !для НЕ (GNU find и BSD find также позволяют -not); обратите внимание, что \!используется в примерах для защиты !от расширений истории оболочки
      • -aдля И (поиск GNU и поиск BSD также позволяют -and)
      • -oдля OR (GNU find и BSD find также позволяют -or)
  • В примерах используются символические режимы, поскольку их легче читать и запоминать.
    • С приставкой режиме -, то =и +операторы могут быть взаимозаменяемыми (например, -u=xэквивалентно -u+x- если вы не применять -xпозже, но нет никакого смысла делать это).
    • Используйте ,для присоединения к частичным режимам; Подразумевается логика И; например, -u=x,g=xозначает, что должны быть установлены и пользовательский, и групповой исполняемый бит.
    • Сами режимы не могут выражать отрицательное совпадение в смысле «совпадение, только если этот бит НЕ установлен»; Вы должны использовать отдельное -permвыражение с НЕ первичным, !.
  • Обратите внимание , что ФАЙНД праймериз (такие как -print, или -perm; также известный как действия и тесты в GNU находке) являются неявно соединены с -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 findGNU find 4.4.2:

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

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

mklement0
источник
2
Самый исчерпывающий ответ SO? ;)
andynormancx
@andynormancx :) Что ж, с точки зрения количества пунктов, я могу предложить этого соперника .
mklement0
11

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

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

(здесь тестовая команда, скорее всего /usr/bin/test, находится в PATH , а не встроенная).


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

gniourf_gniourf
источник
2
Это работает, но довольно медленно. Кроме того, в зависимости от оболочки вам может потребоваться обернуть или избежать заполнителя имени файла, например '{}'или \{\}.
Ionoclast Brigham
1
@ mklement0 это не найдет команды, которые выполняются мной, как это -executableделает или как моя команда.
gniourf_gniourf
1
Спасибо, @gniourf_gniourf - у меня действительно было несколько неправильных представлений. Я перепечатка вашего другой комментария здесь, потому что я по крайней мере , на данный момент удаления моего ответа (возможно , чтобы воскреснуть, если что-то спасти , ): " find . -type f -perm -u=xэто не эквивалент -executable: -executableсоответствует всем файлам, пользователь может выполнять, и они включают g+xесли я нахожусь в правильной группе или o+x. На самом деле -perm -u=xнайду много файлов, которые пользователь не может выполнить, и пропустит несколько, которые пользователь может выполнить ».
mklement0
1
@IonoclastBrigham: Хотя цитирование {}является гипотетической необходимостью (и цитирование не повредит), на практике это не обязательно в POSIX-подобных оболочках и csh. Вы знаете , раковины , где она будет необходима?
mklement0
4
@IonoclastBrigham: Интересно, спасибо; так, в fish, {}действительно должны быть экранированы , как либо '{}'или \{\}. Обратите внимание, что bash, kshи zshобеспечивают такое же расширение скобок; Однако, они не печатать без кавычек фишки {} как (и , таким образом: нет необходимости бежать), потому что они не считают в действительное выражение распорки (они требуют , по крайней мере , 2 лексемы, или действительного выражения числовой последовательности), в то время как fish посчитает действует скрепляющим выражение, которое приводит к пустой строке. {}
mklement0
9

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

-executable
              Matches files which are executable  and  directories  which  are
              searchable  (in  a file name resolution sense).
codaddict
источник
4
-executable предположительно неизвестная опция.
ну на самом деле
4
Будет ли это расширение GNU Find? Поскольку тег относится к Unix, а не к Linux, необходимо как минимум задокументировать расширение GNU.
Джонатан Леффлер,
3
Эта опция не поддерживается командой find BSD, которая есть, по крайней мере, в OS X. Это расширение GNU, но может поддерживаться другими разновидностями find.
Ionoclast Brigham,
FWIW, я обнаружил, что это не на sles 10, а на sles> = 11 (немного обгорел от этого)
Питер Тернер
Обратите внимание, что на самом деле это не все примеры. В моем случае я был файл , который я владел в -rw-r-xr-xкоторый -executableне обнаруживает
Dezza
2

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

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
АджайКумарБашуткар
источник
13
Еще несколько тысяч ящиков, и вы будете изобретать заново file!
tripleee
@tripleee +1. Круто было бы это продление:find ./ -mime application/x-sharedlib -o -mime application/x-dosexec
Дэниел Алдер
@ Дэниел Алдер, какую версию find вы используете? Я не нашел параметр -mime в find (GNU findutils) 4.4.2
AjayKumarBasuthkar
@tripleee +1. использование 'file' и 'mimetype' - хорошая идея, или лучше найти версию, которая поддерживает -mime. Также интересно, есть ли у 'file' / 'mimetype' возможность фильтровать и отображать только исполняемые файлы.
AjayKumarBasuthkar
2
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 . -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, что это за разделитель.

louigi600
источник
1

Это НАСТОЛЬКО смешно, что это не супер-просто ... не говоря уже о почти невозможном . Поднимите руки, я полагаюсь на Apple / Spotlight ...

mdfind 'kMDItemContentType=public.unix-executable'

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

Алекс Грей
источник
Полезно знать об mdfindOSX. Обратите внимание, что команда uour сообщает исполняемые файлы Unix для всей системы . mdfind -onlyin . 'kMDItemContentType=public.unix-executable'ограничивает результаты поддеревом текущего каталога. Незначительный интерес: ограничение поиска только определенным каталогом (без подпапок), по-видимому, не поддерживается. Символьные ссылки на исполняемые файлы, по-видимому, никогда не включаются. Любопытно, что после того mdfind, как файл был обнаружен как исполняемый, последующее удаление исполняемого бита не выполняется .
mklement0
Я думаю, что обнаружил ошибки в том, как Spotlight обнаруживает / не обнаруживает исполняемые файлы Unix; Я зарегистрировал ошибку в Apple, а также на openradar.me/20162683 . Я призываю вас - и всех, кто интересуется этой функциональностью - также
сообщить
(Извините за шквал комментариев; надеюсь, теперь они правы) mdfind -onlyin . 'kMDItemContentType=public.unix-executable'ведет себя как и find . -type f -perm +111 -printделает. То есть он находит файлы с любым установленным исполняемым битом, что может привести к ложным срабатываниям (хотя на практике это может не быть проблемой) - чтобы действительно найти только файлы, исполняемые текущим пользователем, используя поиск BSD, см. Ответ @ gniourf_gniourf. findПреимущество использования решения на основе -основы состоит в том, что при желании вы также можете найти символические ссылки на исполняемые файлы (опция -L), что, по- mdfindвидимому, невозможно.
mklement0
1
@ mklement0 мой ответ избегал приукрашивания - чтобы попытаться докопаться до сути - но да, вы почти никогда не использовали бы эту форму «без прикрас». другой вариант - не уверен, придет ли он - старый добрый шарик .. ls /Applications/**/*(*)в твоей (моей?) zshоболочке
Alex Grey
Спасибо за полезный zshсовет - не знал этого; (кажется , что вы можете либо соответствовать исполняемым файлам ( *) или символьных ссылки ( @), но не оба, правда?). Что касается вашего исходного положения: позвольте мне повторить: find . -type f -perm +a=xбудет делать то, что делает ваша mdfindкоманда, обеспечивая большую гибкость. Вы даже можете переформулировать его, чтобы он был совместим с POSIX.
mklement0
1

Что ж, простой ответ будет: «ваши исполняемые файлы находятся в каталогах, содержащихся в вашей переменной PATH», но на самом деле они не найдут ваши исполняемые файлы и все равно могут пропустить много исполняемых файлов.

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

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

find . -type f -perm +111 -print

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

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

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

louigi600
источник
1

Так что, если вы действительно хотите найти типы исполняемых файлов (например, скрипты, двоичные файлы 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, которая в основном объединяет этот небольшой тест для вас, так что вы можете сократить командную строку, если найдете ее. Но этот способ является более гибким, поскольку вы можете легко заменить == test на = ~ test и использовать его для проверки более сложных свойств, таких как исполняемые текстовые файлы или любую другую информацию, возвращаемую вашей файловой командой.


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

Питер Гердес
источник
0

У меня была такая же проблема, и ответ был в исходном коде 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)
Джосуа Демангеон
источник