148

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

4

10 回答 10

229

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

find . -type f -executable -print

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

find . -type f -perm +111 -print

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

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

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

于 2010-12-16T07:26:46.360 回答
45

@gniourf_gniourf 致敬,以澄清一个基本的误解。

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

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

  • 以用户为中心:查找当前用户可执行的文件。
  • 以文件为中心:查找设置了(一个或多个)可执行权限位文件。

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

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

以用户为中心 ( -executable)

  • 公认的答案值得称赞的是,如果GNU可用。-executable find

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

    • -perm回答以用户为中心的问题是不可能的,因为需要文件的用户和组身份与当前用户的身份相关联,而-perm只能测试文件的权限。
      仅使用POSIXfind功能,如果不涉及外部实用程序,就无法回答这个问题。
    • 因此,(就其本身)所能做的最好的-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,使用-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
      

以文件为中心 ( -perm)

  • 回答以文件为中心的问题使用符合 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 逻辑实现了一个额外的非标准前缀,但使用不兼容的语法
        • BSD 发现:+
        • GNU 发现:/ [2]
      • 因此,如果您的代码必须是可移植的,请避免使用这些扩展。
  • 下面的示例演示了各种以文件为中心的问题的可移植答案。

以文件为中心的命令示例

笔记:

  • 以下示例是 POSIX-compliant,这意味着它们应该在任何 POSIX 兼容的实现中工作,包括 GNU find 和 BSD find;具体来说,这需要:
    • 不使用非标准模式前缀+/.
    • 使用 POSIX 形式的逻辑运算符原语
      • !for NOT(GNU find 和 BSD find 也允许-not);请注意,\!示例中使用它以防止!shell 历史扩展
      • -afor AND (GNU find 和 BSD find 也允许-and)
      • -ofor OR (GNU find 和 BSD find 也允许-or)
  • 这些示例使用符号模式,因为它们更易于阅读和记忆。
    • 使用 mode prefix -=and+运算符可以互换使用(例如,-u=x等效于-u+x- 除非您-x稍后应用,但这样做没有意义)。
    • 用于,加入部分模式;暗含 AND 逻辑;例如,-u=x,g=x意味着必须设置用户和组可执行位。
    • 模式本身不能在“仅当该位未设置时才匹配”的意义上表达否定匹配;您必须使用带有 NOT 主要的单独-perm表达式,!.
  • 请注意,find 的主要元素(例如-print, 或;在 GNU find 中-perm也称为操作测试)隐含地-a(逻辑 AND)连接,并且可能需要括号(作为和对于 shell-o转义)来实现 OR 逻辑。\(\)
  • find -L ...而不是 justfind ...用于将符号链接也匹配到可执行文件
    • -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]-executableman findGNU find 4.4.2 开始的描述:

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

[2] GNU find 4.5.12之前的版本也允许使用 prefix +,但这首先被弃用并最终被删除,因为+符号模式结合可能会产生意想不到的结果,因为它被解释为精确的权限掩码。如果您 (a)在4.5.12之前的版本上运行并且(b) 将自己限制为仅使用八进制模式,可以+同时使用GNU find 和 BSD find,但这不是一个好主意。

于 2015-03-13T18:11:47.847 回答
13

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

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

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


1仅当-executableflagfind不可用时才使用此选项!这与解决方案略有不同-perm +111

于 2014-04-29T12:25:08.830 回答
10

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

-executable
              Matches files which are executable  and  directories  which  are
              searchable  (in  a file name resolution sense).
于 2010-12-16T06:44:05.637 回答
5
find . -executable -type f

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

chmod a+x image.jpg

上面的 find 会认为 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 您的分隔符是什么。

于 2016-03-11T09:51:09.453 回答
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
于 2013-11-28T06:49:43.307 回答
1

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

mdfind 'kMDItemContentType=public.unix-executable'

至少它有效!

于 2015-03-13T17:13:58.650 回答
1

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

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

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

find . -type f -perm +111 -print

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

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

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

于 2016-03-21T11:16:52.030 回答
1

我遇到了同样的问题,答案在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)
于 2016-07-26T17:00:29.093 回答
1

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

 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:

 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.


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.

于 2019-04-05T13:26:46.927 回答