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


113

我可以在Unix find命令中使用哪种类型的参数/标志,以便搜索可执行文件?


输入“查找人”。我认为“可执行”是您想要的选项。
sje397

3
find -executable...但是这不能保证列出的每个文件都会真正执行
William 2010年

1
并非所有的实现find都是平等的。@ sje397和@William推荐的选项可能不可用。最好使用下面显示的公认解决方案
LS


我不喜欢下面显示的所有基于文件权限的建议。参数:对于我的GNU操作系统(Ubuntu),可以为例如ASCII文本文件设置“ x”(可执行)标志。没有模仿者阻止此操作成功完成。对于多个非故意的文件,只需很小的错误/错误即可分配x标志。因此,gniourf_gniourf的解决方案是我个人的最爱。然而,其缺点在于,对于交叉编译的可执行文件,需要仿真器或目标设备。
Na13-c

Answers:


173

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

find . -type f -executable -print

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

find . -type f -perm +111 -print

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

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

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


find: invalid mode ‘+111’findutils 4.5.11 4.fc20 错误。
sourcejedi 2014年

1
@sourcejedi谢谢。我实际上只是在谈论非GNU版本的find(尤其是BSD),但旧版GNU find实际上也确实支持该语法。在较新的版本中,您必须使用/代替+。有关更多详细信息,请参见更新后的答案。
劳伦斯·贡萨尔维斯

确实,我看错了你的答案。很抱歉,它变得更加复杂:)。
sourcejedi 2014年

如果还应找到指向可执行文件的符号链接,请包括以下-L选项:find -L ...
mklement0

我花了一些时间来理解“与-executable谓词不同”和“仅测试是否设置了任何执行权限”的含义:这意味着-perm +111可能会产生误报,即当前用户无法实际执行的文件。不能-executable仅通过测试权限来进行仿真,因为所需的是将文件的用户和组标识与当前用户的关联
mklement0

35

提示@ gniourf_gniourf可以消除基本的误解。

该答案试图提供现有答案概述,讨论它们的精妙之处相对优点,并提供背景信息,特别是在便携性方面

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

  • 以用户为中心:查找当前用户可执行的文件
  • 以文件为中心:发现有文件(一个或多个)可执行权限位

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

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

以用户为中心(-executable

  • 接受的答案值得称赞的建议-executable,IF GNU find是可用的。

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

    • 只需使用-perm回答用户 -centric问题是不可能的,因为我们需要的是对有关文件的用户和组身份给当前用户的,而-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不必为每个文件都调用(以下内容使用BSD find -perm +111/ GNU find 的POSIX兼容等效物-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都实现了一个附加的非标准前缀具有指定权限位集逻辑,但使用不兼容的语法
        • BSD找到: +
        • GNU查找:/ [2]
      • 因此,如果您的代码必须是可移植的,请避免使用这些扩展名
  • 下面的示例演示了对各种以文件为中心的问题的可移植答案。

以文件为中心的命令示例

注意:

  • 以下示例符合POSIX规范,这意味着它们应可在任何POSIX兼容实现中使用,包括GNU find和BSD find。具体来说,这要求:
    • 不使用非标准模式前缀+/
    • 使用POSIX形式的逻辑运算符原语
      • !对于NOT(GNU查找和BSD查找也允许-not);请注意,\!在示例中使用该命令是为了防止!shell历史记录扩展
      • -a用于AND(GNU查找和BSD查找也允许-and
      • -o用于OR(GNU查找和BSD查找也允许-or
  • 这些示例使用符号模式,因为它们更易于阅读和记住。
    • 使用mode前缀时-=and +运算符可以互换使用(例如,-u=x等效于-u+x-除非-x以后再应用,但这没有任何意义)。
    • 使用,加入部分模式; 暗含AND逻辑;例如,-u=x,g=x意味着必须同时设置用户组可执行位。
    • 模式本身不能表示否定匹配,即“仅当未设置此位时才匹配”。您必须使用-perm带有非主要符号的单独表达式!
  • 需要注意的是发现的初选(如-print,或-perm;也被称为行动测试在GNU发现)的隐含与加盟-a(逻辑与),以及-o和可能的括号(转义为\(\)的壳),需要执行或逻辑。
  • find -L ...find ...为了使符号链接也与可执行文件 匹配,使用了不只是
    • -L指示发现评估符号链接的目标,而不是符号链接本身;因此,如果没有-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映射(或根压缩)的NFS服务器所欺骗,因为许多系统在客户端的内核中实现了access(2),因此无法利用服务器上保存的UID映射信息。因为此测试仅基于access(2)系统调用的结果,所以不能保证可以成功执行该测试成功的文件。

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


2
有史以来最全面的答案?;)
andynormancx

@andynormancx :)好吧,就子弹点的绝对数量而言,我可以提供这个竞争者
mklement0 '18

11

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

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

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


1仅当-executable标记find不可用时才使用此功能!这与-perm +111解决方案有细微的差别。


2
这可行,但是速度很慢。另外,根据外壳的不同,您可能必须包装或转义文件名占位符,例如'{}'\{\}
Ionoclast Brigham 2014年

1
@ mklement0这将找不到我可以执行的命令-executable或类似我的命令执行的命令。
gniourf_gniourf 2015年

1
谢谢,@ gniourf_gniourf-我真的在那儿有一些误解。我在这里重新打印其他评论,因为我至少现在删除我的答案(也许是被复活,如果有什么补救的):“ find . -type f -perm -u=x不是相当于-executable-executable匹配用户可以执行所有文件,其中包括g+x如果我属于适当的组,则o+x实际上-perm -u=x会找到许多用户无法执行的文件,而错过了一些用户可以执行的文件。”
mklement0

1
@IonoclastBrigham:虽然必须引用{}是一种假设性的必要(并且引用也无害),但实际上在类似POSIX的shell和中没有必要csh。你知道炮弹其中它必需的?
mklement0 2015年

4
@IonoclastBrigham:有趣,谢谢;因此,in fish{}必须确实以'{}'或进行转义\{\}。需要注意的是bashkshzsh提供同类括号扩展的; 然而,它们打印无引号标记{} 为是(并且因此:无需逸出),因为它们不认为这是一种有效的括号表达式(它们需要至少2代币,或有效的数字序列表达式),而fish 认为{}一个有效撑导致字符串的表达式。
mklement0 2015年

9

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

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

4
-executable应该是一个未知选项。
实际上是2010年

4
那会是GNU Find扩展吗?由于标签是Unix,而不是Linux,因此至少需要这样记录GNU扩展名。
乔纳森·莱夫勒

3
至少在OS X上找到的BSD find命令不支持此选项。这是GNU扩展,但其他形式的find可能也支持。
Ionoclast Brigham 2012年

FWIW,我发现这不是在10根草地上,而是在> = 11根草地上(有点烫了)
Peter Turner

请注意,这实际上并没有获得所有示例。在我来说,我有我所拥有的文件,-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
2013年

@tripleee +1。扩展将是很酷的:find ./ -mime application/x-sharedlib -o -mime application/x-dosexec
Daniel Alder 2014年

@Daniel Alder,您使用哪个版本的查找?我在find(GNU findutils)4.4.2中找不到选项-mime
AjayKumarBasuthkar 2014年

@tripleee +1。利用'file'&/'mimetype'是个好主意,或者发现支持-mime的查找版本更好。还想知道'file'/'mimetype'是否具有仅过滤和显示可执行文件的选项。
AjayKumarBasuthkar 2014年

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分隔符是什么。


1

真是太荒谬了,这不是一件容易的事,更不用说几乎不可能了。举起手来,我遵从Apple / Spotlight ...

mdfind 'kMDItemContentType=public.unix-executable'

至少有效!


mdfind高兴在OSX 上了解。注意,您的命令报告了整个系统的 Unix可执行文件。mdfind -onlyin . 'kMDItemContentType=public.unix-executable'将结果限制为当前目录的子树。次要景点:不支持仅将搜索限制到特定目录(不包含子文件夹)。显然从未包含指向可执行文件的符号链接。奇怪的是,一旦mdfind找到了可执行文件,随后就不会删除可执行文件。
mklement0

我认为我发现了Spotlight如何检测/不检测可执行Unix文件的错误。我已经与Apple以及openradar.me/20162683一起提交了错误。我鼓励你-和任何人有兴趣在此功能-也以文件的错误错误bugreport.apple.com
mklement0

(很抱歉,您的评论很乱;希望它们现在是正确的)的mdfind -onlyin . 'kMDItemContentType=public.unix-executable'行为与实际find . -type f -perm +111 -print情况相同。也就是说,它查找具有任何可执行位的文件,这可能会产生误报(尽管在实践中可能不是问题)-要真正仅使用BSD find查找当前用户可执行的文件,请参见@gniourf_gniourf的答案。使用find基于解决方案的优点是,您可以找到指向可执行文件的符号链接(如果需要)(选项-L),这mdfind似乎是做不到的。
mklement0

1
@ mklement0我的回答避开了装饰 -试图确定要点-但是,是的,您几乎永远不会使用这种“未经装饰”的形式。另一种选择-不知道它拿出-是好老通配 .. ls /Applications/**/*(*)在你(我的?)zsh
亚历克斯·格雷

感谢您的便捷zsh提示-不知道;(看来你可以任意匹配的可执行文件(*符号链接(@),但不能同时,对吧?)。关于您的原始观点:让我重申find . -type f -perm +a=x一下:mdfind在提供更多灵活性的同时,将执行您的命令所执行的操作。您甚至可以将其重新构造为符合POSIX的格式。
mklement0 2015年

1

答案很简单:“您的可执行文件位于PATH变量包含的目录中”,但这实际上找不到您的可执行文件,并且可能会丢失很多可执行文件。

我对Mac不太了解,但我认为“ mdfind'kMDItemContentType = public.unix-executable'”可能会遗漏解释脚本等内容

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

find . -type f -perm +111 -print

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

也许将来find会支持“ -magic”,并让您显式查找具有特定魔术ID的文件...但是您必须指定以优化所有可执行格式的魔术ID。

我不知道在UNIX上技术上正确的简便方法。


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的小实用程序,该实用程序基本上为您捆绑了该小测试,因此,如果找到它,则可以缩短命令行。但是这种方式更加灵活,因为您可以轻松地将==测试替换为=〜测试,并使用它来检查更复杂的属性,例如可执行的纯文本文件或file命令返回的任何其他信息。


此处确切的报价规则非常模糊,因此我最终还是通过反复试验得出结论,但我希望听到正确的解释。


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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.