bash 使用 find 命令搜索可执行文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4458120/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 19:58:15  来源:igfitidea点击:

Search for executable files using find command

bashunixterminalfindfind-util

提问by well actually

What type of parameter/flag can I use with the Unix findcommand so that I search executables?

我可以在 Unixfind命令中使用什么类型的参数/标志来搜索可执行文件?

回答by Laurence Gonsalves

On GNU versions of find you can use -executable:

在 GNU 版本的 find 上,您可以使用-executable

find . -type f -executable -print

For BSD versions of find, you can use -permwith +and an octal mask:

对于 BSD 版本的 find,您可以使用-permwith+和一个八进制掩码:

find . -type f -perm +111 -print

In this context "+" means "any of these bits are set" and 111 is the execute bits.

在这种情况下,“+”表示“设置了这些位中的任何一个”,而 111 是执行位。

Note that this is not identical to the -executablepredicate in GNU find. In particular, -executabletests that the file can be executed by the current user, while -perm +111just tests if any execute permissions are set.

请注意,这与-executableGNU find 中的谓词不同。特别是,-executable测试当前用户可以执行该文件,而-perm +111只测试是否设置了任何执行权限。

Older versions of GNU find also support the -perm +111syntax, but as of 4.5.12this syntax is no longer supported. Instead, you can use -perm /111to get this behavior.

旧版本的 GNU find 也支持该-perm +111语法,但从4.5.12 开始不再支持该语法。相反,您可以使用-perm /111来获取此行为。

回答by mklement0

Tip of the hat to @gniourf_gniourffor clearing up a fundamental misconception.

尖帽子@的gniourf_gniourf清除了一个根本性的误解。

This answer attempts to provide an overview of the existing answersand to discuss their subtletiesand relative meritsas well as to provide background information, especially with respect to portability.

此答案试图提供现有答案概述,并讨论它们的微妙之处相对优点,并提供背景信息,尤其是在可移植性方面

Finding files that are executable can refer to two distinct use cases:

查找可执行文件可以指两个不同的用例

  • user-centric: find files that are executable by the current user.
  • file-centric: find files that have (one or more) executable permission bitsset.
  • 以用户为中心:查找当前用户可执行的文件
  • 以文件为中心:发现有文件(一个或多个)可执行权限位

Note that in eitherscenario it may make sense to use find -L ...instead of just find ...in order to also find symlinks toexecutables.

请注意,在这两种情况下,使用find -L ...而不是仅仅find ...为了找到指向可执行文件的符号链接可能是有意义的。

Note that the simplest file-centric case - looking for executables with the executable permissions bit set for ALL three security principals (user, group, other) - will typically, but not necessarilyyield the same results as the user-centric scenario - and it's important to understand the difference.

请注意,最简单的以文件为中心的情况——寻找为所有三个安全主体(用户、组、其他)设置了可执行权限位的可执行文件——通常,但不一定会产生与以用户为中心的场景相同的结果——它是了解差异很重要。

User-centric (-executable)

以用户为中心 ( -executable)

  • The accepted answercommendably recommends -executable, IF GNUfindis available.

    • GNU findcomes with most Linuxdistros
      • By contrast, BSD-based platforms, including macOS, come with BSD find, which is less powerful.
    • As the scenario demands, -executablematches only files the current usercan execute (there are edge cases.[1]).
  • The BSDfindalternative offered by the accepted answer (-perm +111)answers a different, file-centric question(as the answer itself states).

    • Using just -permto answer the user-centric question is impossible, because what is needed is to relatethe file'suser and group identity to the current user's, whereas -permcan only test the file'spermissions.
      Using only POSIX findfeatures, the question cannot be answered without involving external utilities.
    • Thus, the best -permcan do (by itself) is an approximationof -executable. Perhaps a closerapproximation than -perm +111is -perm -111, so as to find files that have the executable bit set for ALL security principals (user, group, other) - this strikes me as the typical real-world scenario. As a bonus, it also happens to be POSIX-compliant (use find -Lto include symlinks, see farther below for an explanation):

      find . -type f -perm -111  # or: find . -type f -perm -a=x
      
  • gniourf_gniourf's answerprovides a true, portable equivalent of -executable, using -exec test -x {} \;, albeit at the expense of performance.

    • Combining-exec test -x {} \;with -perm +111(i.e., files with at least oneexecutable bit set) may help performance in that execneedn't be invoked for everyfile (the following uses the POSIX-compliant equivalent of BSD find -perm +111/ GNU find -perm /111; see farther below for an explanation):

      find . -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \) -exec test -x {} \; -print
      
  • 接受的答案值得称赞的建议-executable,IF GNUfind是可用的。

    • GNUfind随大多数Linux发行版一起提供
      • 相比之下,基于 BSD 的平台(包括 macOS)带有 BSD find,但功能较弱。
    • 根据场景要求,-executable仅匹配当前用户可以执行的文件(存在边缘情况。[1])。
  • 接受的答案 ( )提供BSDfind替代方案-perm +111回答了一个不同的、以文件为中心的问题(正如答案本身所述)。

    • 只需使用-perm回答用户-centric问题是不可能的,因为我们需要的是对有关文件的用户和组身份给当前用户的,而-perm只能测试文件的权限。
      仅使用POSIX findfeatures,如果不涉及外部实用程序就无法回答这个问题。
    • 因此,最好-perm能(本身)做的是一个近似-executable也许比is接近-perm +111-perm -111,以便找到为所有安全主体(用户、组、其他)设置了可执行位的文件 - 这让我觉得这是典型的现实世界场景。作为奖励,它也恰好是 POSIX 兼容的(用于find -L包含符号链接,请参阅下面的更多解释):

      find . -type f -perm -111  # or: find . -type f -perm -a=x
      
  • gniourf_gniourf 的回答提供了一个真正的、可移植的等价物-executable, using-exec test -x {} \;,尽管以牺牲性能为代价

    • 结合-exec test -x {} \;使用-perm +111(即,具有至少一个可执行位集的文件)可能有助于提高性能,因为exec不需要为每个文件调用(以下使用符合 POSIX 的 BSD find -perm +111/ GNU find等价物-perm /111;有关解释,请参见下文) :

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

File-centric (-perm)

以文件为中心 ( -perm)

  • To answer file-centric questions, it issufficient to use the POSIX-compliant -permprimary(known as a testin GNU find terminology).
    • -permallows you to test for anyfile permissions, not just executability.
    • Permissions are specified as either octalor symbolic modes. Octal modes are octal numbers (e.g., 111), whereas symbolic modes are strings (e.g., a=x).
    • Symbolic modesidentify the security principals as u(user), g(group) and o(other), or ato refer to all three. Permissions are expressed as xfor executable, for instance, and assigned to principals using operators =, +and -; for a full discussion, including of octal modes, see the POSIX spec for the chmodutility.
    • In the context of find:
      • Prefixing a mode with -(e.g., -ug=x) means: match files that have allthe permissions specified(but matching files may have additional permissions).
      • Having NO prefix(e.g. 755) means: match files that have this full, exactset of permissions.
      • Caveat: Both GNU find and BSD findimplement an additional, nonstandardprefixwith are-ANY-of-the-specified-permission-bits-set logic, but do so with incompatible syntax:
        • BSD find: +
        • GNU find: /[2]
      • Therefore, avoid these extensions, if your code must be portable.
  • The examples below demonstrate portable answers to various file-centric questions.
  • 回答以文件为中心的问题使用符合 POSIX 的主要(在 GNU 查找术语中称为测试足够了-perm
    • -perm允许您测试任何文件权限,而不仅仅是可执行性。
    • 权限被指定为八进制符号模式。八进制模式是八进制数(例如,111),而符号模式是字符串(例如,a=x)。
    • 符号模式将安全主体标识为u(用户)、g(组)和o(其他),或a指代所有三者。x例如,权限表示为可执行文件,并使用运算符=+-;分配给主体。有关包括八进制模式在内的完整讨论,请参阅实用程序的 POSIX 规范chmod
    • 在以下情况下find
      • -(例如,-ug=x为模式前缀意味着:匹配具有指定所有权限的文件(但匹配的文件可能具有额外的权限)。
      • 没有前缀(如755)是指:具有此匹配的文件完整,准确的权限。
      • 警告GNU find 和 BSD find使用are-ANY-of-the-specified-permission-bits-set logic实现了一个额外的非标准前缀,但这样做的语法不兼容
        • BSD 发现: +
        • GNU 发现:/[2]
      • 因此,如果您的代码必须是可移植的,请避免使用这些扩展
  • 下面的示例演示了各种以文件为中心的问题的可移植答案。


File-centric command examples

以文件为中心的命令示例

Note:

笔记:

  • The following examples are POSIX-compliant, meaning they should work in any POSIX-compatible implementation, including GNU find and BSD find; specifically, this requires:
    • NOT using nonstandard mode prefixes +or /.
    • Using the POSIX forms of the logical-operator primaries:
      • !for NOT (GNU find and BSD find also allow -not); note that \!is used in the examples so as to protect !from shell history expansions
      • -afor AND (GNU find and BSD find also allow -and)
      • -ofor OR (GNU find and BSD find also allow -or)
  • The examples use symbolicmodes, because they're easier to read and remember.
    • With mode prefix -, the =and +operators can be used interchangeably (e.g., -u=xis equivalent to -u+x- unless you apply -xlater, but there's no point in doing that).
    • Use ,to join partial modes; AND logic is implied; e.g., -u=x,g=xmeans that both the user andthe group executable bit must be set.
    • Modes cannot themselvesexpress negative matching in the sense of "match only if this bit is NOT set"; you must use a separate -permexpression with the NOT primary, !.
  • Note that find's primaries(such as -print, or -perm; also known as actionsand testsin GNU find) are implicitlyjoined with -a(logical AND), and that -oand possibly parentheses (escaped as \(and \)for the shell) are needed to implement OR logic.
  • find -L ...instead of just find ...is used in order to also match symlinks toexecutables
    • -Linstructs find to evaluate the targetsof symlinks instead of the symlinks themselves; therefore, without -L, -type fwould ignore symlinks altogether.
  • 以下示例符合 POSIX 标准,这意味着它们应该适用于任何兼容 POSIX 的实现,包括 GNU find 和 BSD find;具体来说,这需要:
    • 不使用非标准模式前缀+/.
    • 使用逻辑运算符原语的 POSIX 形式:
      • !对于 NOT(GNU find 和 BSD find 也允许-not);请注意,\!在示例中使用它是为了防止!shell 历史扩展
      • -a对于 AND(GNU find 和 BSD find 也允许-and
      • -o用于 OR(GNU 查找和 BSD 查找也允许-or
  • 这些示例使用符号模式,因为它们更易于阅读和记忆。
    • 使用 mode prefix -=and+运算符可以互换使用(例如,-u=x等效于-u+x- 除非您-x稍后申请,但这样做没有意义)。
    • 使用,加入部分模式; AND 逻辑是隐含的;例如,-u=x,g=x意味着必须设置用户组可执行位。
    • 模式本身不能表达“仅在未设置此位时才匹配”的意义上的否定匹配;您必须使用-perm带有 NOT 主要的单独表达式,!.
  • 需要注意的是发现的初选(如-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] Description of -executablefrom man findas of GNU find 4.4.2:

[1]-executable来自man findGNU find 4.4.2 的描述:

Matches files which are executable and directories which are searchable (in a file name resolution sense). This takes into account access control lists and other permissions artefacts which the -perm test ignores. This test makes use of the access(2) system call, and so can be fooled by NFS servers which do UID mapping (or root-squashing), since many systems implement access(2) in the client's kernel and so cannot make use of the UID mapping information held on the server. Because this test is based only on the result of the access(2) system call, there is no guarantee that a file for which this test succeeds can actually be executed.

匹配可执行文件和可搜索目录(在文件名解析意义上)。这考虑了 -perm 测试忽略的访问控制列表和其他权限人工制品。该测试使用了 access(2) 系统调用,因此可能会被执行 UID 映射(或根压缩)的 NFS 服务器所欺骗,因为许多系统在客户端内核中实现了 access(2),因此无法使用服务器上保存的 UID 映射信息。由于此测试仅基于 access(2) 系统调用的结果,因此无法保证此测试成功的文件确实可以执行。

[2] GNU find versions older than 4.5.12also allowed prefix +, but this was first deprecated and eventually removed, because combining +with symbolicmodes yields likely yields unexpected results due to being interpreted as an exactpermissions mask. Ifyou (a) run on a version before4.5.12 and(b) restrict yourself to octalmodes only, you couldget away with using +with bothGNU find and BSD find, but it's not a good idea.

[2]早于 4.5.12 的GNU find 版本也允许使用 prefix +,但这首先被弃用并最终被删除,因为+符号模式结合可能会产生意外结果,因为被解释为精确的权限掩码。如果您(a)在版本上运行之前4.5.12(二)限制自己八进制模式而已,你可以摆脱使用+这两个GNU发现和BSD的发现,但它不是一个好主意。

回答by gniourf_gniourf

So as to have another possibility1to find the files that are executable by the current user:

以便有另一种可能性1找到当前用户可执行的文件:

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

(the test command here is the one found in PATH, very likely /usr/bin/test, not the builtin).

(这里的测试命令是在 PATH 中找到的,很可能是/usr/bin/test,而不是内置命令)。



1Only use this if the -executableflag of findis not available! this is subtly different from the -perm +111solution.

1只有在-executable标志find不可用时才使用它!这与-perm +111解决方案略有不同。

回答by codaddict

You can use the -executabletest flag:

您可以使用-executable测试标志:

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

回答by AjayKumarBasuthkar

This worked for me & thought of sharing...

这对我有用并想分享...

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

回答by louigi600

find . -executable -type f

does not really guarantee that the file is executable it will find files with the execution bit set. If you do

并不能真正保证文件是可执行的,它会找到设置了执行位的文件。如果你这样做

chmod a+x image.jpg

the above find will think image.jpg is an executable even if it is really a jpeg image with the execution bit set.

上面的 find 会认为 image.jpg 是一个可执行文件,即使它确实是一个设置了执行位的 jpeg 图像。

I generally work around the issue with this:

我通常解决这个问题:

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

If you want the find to actually print dome information about executable files you can do something like this:

如果您希望 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

In the above example the file's full pathname is in the last field and must reflect where you look for it with awk "NAME=$(awk '{print $NF}' <<< $LINE)" if the file name was elsewhere in the find output string you need to replace "NF" with the correct numerical position. If your separator is not space you also need to tell awk what your separator is.

在上面的示例中,文件的完整路径名位于最后一个字段中,并且如果文件名位于其他位置,则必须使用 awk "NAME=$(awk '{print $NF}' <<< $LINE)"您需要用正确的数字位置替换“NF”的查找输出字符串。如果您的分隔符不是空格,您还需要告诉 awk 您的分隔符是什么。

回答by louigi600

Well the easy answer would be: "your executable files are in the directories contained in your PATH variable" but that would not really find your executables and could miss a lot of executables anyway.

好吧,简单的答案是:“您的可执行文件位于 PATH 变量中包含的目录中”,但这不会真正找到您的可执行文件,并且无论如何都可能会错过很多可执行文件。

I don't know much about mac but I think "mdfind 'kMDItemContentType=public.unix-executable'" might miss stuff like interpreted scripts

我对 mac 不太了解,但我认为“mdfind 'kMDItemContentType=public.unix-executable'”可能会错过解释脚本之类的东西

If it's ok for you to find files with the executable bits set (regardless of whether they are actually executable) then it's fine to do

如果您可以找到设置了可执行位的文件(无论它们是否实际可执行),那么就可以了

find . -type f -perm +111 -print

where supported the "-executable" option will make a further filter looking at acl and other permission artifacts but is technically not much different to "-pemr +111".

支持“-executable”选项将进一步过滤查看 acl 和其他权限工件,但在技术上与“-pemr +111”没有太大区别。

Maybe in the future find will support "-magic " and let you look explicitly for files with a specific magic id ... but then you would haveto specify to fine all the executable formats magic id.

也许将来 find 将支持“-magic”并让您明确查找具有特定魔术 ID 的文件……但是您必须指定对所有可执行格式魔术 ID 进行细化。

I'm unaware of a technically correct easy way out on unix.

我不知道在 unix 上有一种技术上正确的简单方法。

回答by Alex Gray

It is SO ridiculousthat this is not super-easy... let alone next to impossible. Hands up, I defer to Apple/Spotlight...

太荒谬了,这不是超级容易……更不用说几乎不可能了。举起手来,我听从 Apple/Spotlight...

mdfind 'kMDItemContentType=public.unix-executable'

mdfind 'kMDItemContentType=public.unix-executable'

At least it works!

至少它有效!

回答by Peter Gerdes

So if you actually want to find executable file types (e.g. scripts, ELF binaries etc.. etc..) not merely files with execution permissionthen you probably want to do something more like this (where the current directory . can be replaced with whatever directory you want):

因此,如果您实际上想要查找可执行文件类型(例如脚本、ELF 二进制文件等),而不仅仅是具有执行权限的文件,那么您可能想要做更多类似的事情(当前目录 . 可以替换为任何你想要的目录):

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

Or for those of you who aren't using macports (linux users) or otherwise have gnu find installed as find you want:

或者对于那些不使用 macports(linux 用户)或以其他方式安装 gnu find 的人来说:

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

Though if you are on OS X it comes with a little utility hidden somewhere called is_exec that basically bundles up that little test for you so you can shorten the command line if you find it. But this way is more flexible as you can easily replace the == test with the =~ test and use it to check for more complex properties like executable plain text files or whatever other info your file command returns.

尽管如果您使用的是 OS X,它会带有一个隐藏在某处的小实用程序,称为 is_exec,它基本上为您捆绑了该小测试,因此您可以在找到它时缩短命令行。但这种方式更灵活,因为您可以轻松地将 == 测试替换为 =~ 测试,并使用它来检查更复杂的属性,例如可执行纯文本文件或文件命令返回的任何其他信息。



The exact rules for quotation here are pretty opaque so I just end up working it out by trial and error but I'd love to hear the right explanation.

这里引用的确切规则非常不透明,所以我只是通过反复试验来解决它,但我很想听到正确的解释。

回答by Josuah Demangeon

I had the same issue, and the answer was in the dmenu source code: the stest utility made for that purpose. You can compile the 'stest.c' and 'arg.h' files and it should work. There is a man page for the usage, that I put there for convenience:

我遇到了同样的问题,答案在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)