【问题标题】:Search for executable files using find command使用 find 命令搜索可执行文件
【发布时间】:2011-05-26 09:07:00
【问题描述】:

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

【问题讨论】:

  • 键入“人查找”。我认为“-executable”是您想要的选项。
  • find -executable ... 但这并不能保证列出的每个文件都会实际执行
  • 并非所有find 的实现都是一样的。 @sje397 和@William 推荐的选项可能不可用。最好使用如下所示的accepted solution
  • 我不喜欢下面显示的所有基于文件权限的建议。论证:对于我的 GNU 操作系统(Ubuntu),可以为例如 ASCII 文本文件设置“x”(可执行)标志。没有模仿阻止此操作成功完成。多个非预期文件只需小错误/错误即可分配 x 标志。因此 gniourf_gniourf 的解决方案是我个人的最爱。然而,它的缺点是交叉编译的可执行文件需要模拟器或目标设备。

标签: bash unix terminal find find-util


【解决方案1】:

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

find . -type f -executable -print

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

find . -type f -perm +111 -print

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

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

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

【讨论】:

  • 在 findutils 4.5.11 4.fc20 上出现错误 find: invalid mode ‘+111’
  • @sourcejedi 谢谢。我实际上只是在谈论非 GNU 版本的 find(尤其是 BSD),但旧版本的 GNU find 实际上也支持该语法。在较新的版本中,您必须使用/ 而不是+。有关详细信息,请参阅更新的答案。
  • 确实,我误读了您的回答。很抱歉让它变得更复杂:)。
  • 如果还应该找到指向可执行文件的符号链接,请包含-L 选项:find -L ...
  • 我花了一段时间才理解“与 -executable 谓词不同”和“仅测试是否设置了 any 执行权限”的含义:这意味着 @ 987654337@ 可能会产生误报,即当前用户无法实际执行的文件。没有办法通过单独测试权限来模拟-executable,因为需要将文件的用户和组身份与当前用户的关联 .
【解决方案2】:

感谢@gniourf_gniourf 澄清一个基本误解。

此答案试图提供现有答案的概述,并讨论它们的微妙之处相对优点,并提供背景信息,尤其是关于便携性

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

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

请注意,在任一场景中,使用find -L ...而不只是find ...可能是有意义的,以便也找到符号链接到 可执行文件

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

以用户为中心 (-executable)

  • accepted answer 值得推荐的是 -executable,如果 GNU find 可用。

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

    • 仅使用-perm 回答以用户为中心的问题是不可能,因为需要的是关联 文件的用户和组标识当前用户的,而-perm只能测试文件的权限。
      仅使用POSIX find features,不涉及外部实用程序就无法回答问题。
    • 因此,-perm 可以做到的最好的(单独)是-executable近似也许比-perm +111 更接近的近似值是-perm -111,以便找到为所有安全主体(用户、组、其他)设置了可执行位的文件 -这让我觉得这是典型的现实世界场景。作为奖励,它也恰好符合 POSIX(使用 find -L 来包含符号链接,请参阅下面的进一步说明):

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

    • 结合 -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 的-perm primary就足够了>(在 GNU 查找术语中称为 测试)。
    • -perm 允许您测试任何文件权限,而不仅仅是可执行性。
    • 权限指定为八进制符号模式。八进制模式是八进制数(例如,111),而符号模式是字符串(例如,a=x)。
    • 符号模式将安全主体标识为u(用户)、g(组)和o(其他),或者a 来指代这三个。例如,对于可执行文件,权限表示为x,并使用运算符=+- 分配给主体;如需完整的讨论,包括八进制模式,请参阅the POSIX spec for the chmod utility
    • find 的上下文中:
      • 在模式前加上-(例如-ug=x)意味着:匹配具有所有指定权限的文件(但匹配的文件可能有额外的权限)。
      • 具有无前缀(例如755)意味着:匹配具有此完整、准确权限集的文件。
      • 警告GNU 查找和 BSD 查找 都使用 are-ANY- 实现了一个附加的非标准前缀 of-the-specified-permission-bits-set logic,但使用不兼容的语法
        • BSD 发现:+
        • GNU 发现:/ [2]
      • 因此,如果您的代码必须可移植,请避免这些扩展。
  • 以下示例演示了各种以文件为中心的问题的可移植答案。

以文件为中心的命令示例

注意:

  • 以下示例符合 POSIX 标准,这意味着它们应该适用于任何 POSIX 兼容的实现,包括 GNU find 和 BSD find;具体来说,这需要:
    • 不使用非标准模式前缀+/
    • 使用 logical-operator primaries 的 POSIX 形式:
      • ! 表示 NOT(GNU 查找和 BSD 查找也允许 -not);请注意,示例中使用了\!,以保护! 免受shell 历史扩展的影响
      • -a 用于 AND(GNU 查找和 BSD 查找也允许 -and
      • -o 用于 OR(GNU 查找和 BSD 查找也允许 -or
  • 示例使用符号模式,因为它们更容易阅读和记忆。
    • 使用模式前缀-=+ 运算符可以互换使用 (例如,-u=x 等价于 -u+x - 除非您稍后应用 -x,但这样做没有意义)。
    • 使用,加入部分模式;暗含 AND 逻辑;例如,-u=x,g=x 表示用户组可执行位都必须设置。
    • 模式自身不能在“仅当此位未设置时才匹配”的意义上表达否定匹配;您必须使用单独的 -perm 表达式和 NOT 主表达式 !
  • 注意 find 的 primaries(例如 -print-perm;在 GNU find 中也称为 actionstests)与-a(逻辑AND)隐式连接,并且需要-o 和可能的括号(转义为\(\) 对于shell)来实现OR 逻辑。李>
  • 使用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) 系统调用,因此可以 被执行 UID 映射(或 root-squashing)的 NFS 服务器所愚弄,因为许多系统在客户端的内核中实现 access(2),因此不能 利用服务器上保存的 UID 映射信息。因为这个测试只基于 access(2) 系统调用的结果,所以有 不能保证此测试成功的文件实际上可以执行。

[2] GNU 查找版本早于 4.5.12 也允许前缀 +,但这首先被弃用并最终被删除,因为将 +symbolic由于被解释为 exact 权限掩码, 模式可能会产生意想不到的结果。 如果您 (a) 在 4.5.12 之前的版本上运行 并且 (b) 将自己限制为 八进制 模式只是,您可以+两者 GNU find 和BSD find 一起使用,但这不是一个好主意。

【讨论】:

  • 有史以来最全面的 SO 答案? ;)
  • @andynormancx :) 好吧,就项目符号的数量而言,我可以提供this contender
【解决方案3】:

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

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

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


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

【讨论】:

  • 这可行,但速度很慢。此外,根据 shell,您可能需要包装或转义文件名占位符,例如 '{}'\{\}
  • @mklement0 这不会像-executable 那样或像我的命令那样找到我可执行的命令。
  • 谢谢,@gniourf_gniourf - 我真的有一些误解。我在这里转载你的其他评论,因为我至少现在要删除我的答案(如果有什么可以挽救的,也许会复活):“find . -type f -perm -u=x not 相当于@987654330 @:-executable 匹配用户可以执行的所有文件,其中包括 g+x(如果我在正确的组中)或 o+x。实际上,-perm -u=x 会找到很多用户无法执行的文件,并且会错过一些用户可以执行的。”
  • @IonoclastBrigham:虽然必须引用{} 是假设的必要性(并且引用并没有坏处),但实际上在类似POSIX 的shell 和csh 中没有必要。您知道需要 的 shell 吗?
  • @IonoclastBrigham:很有趣,谢谢;因此,在fish 中,{} 确实必须转义为'{}'\{\}。请注意bashkshzsh 提供相同类型的大括号扩展;但是,他们打印未引用的标记 {} as is (因此:不需要转义),因为他们不认为它是 valid 大括号表达式(他们需要在最少 2 个标记,或有效的数字序列表达式),而 fish 认为 {} 是一个 有效 大括号表达式,导致 empty字符串。
【解决方案4】:

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

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

【讨论】:

  • -executable 应该是一个未知选项。
  • 那会是 GNU Find 扩展吗?由于标签是 Unix,而不是 Linux,因此至少需要记录一个 GNU 扩展。
  • 至少在 OS X 上找到的 BSD find 命令不支持此选项。这是一个 GNU 扩展,但可能会被其他类型的 find 支持。
  • FWIW,我发现这不是在 sles 10 上,而是在 sles >= 11 上(有点被它烫伤了)
  • 请注意,这实际上并没有得到所有示例。在我的情况下,我有一个文件,我拥有 -rw-r-xr-x-executable 没有检测到
【解决方案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}'

【讨论】:

    【解决方案6】:

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

    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
    

    【讨论】:

    • 再增加几千个案例,您将彻底改造file
    • @tripleee +1。这个扩展很酷:find ./ -mime application/x-sharedlib -o -mime application/x-dosexec
    • @Daniel Alder,您使用哪个版本的 find?我在 find (GNU findutils) 4.4.2 中没有找到选项 -mime
    • @tripleee +1。使用 'file' 和/ 'mimetype' 是个好主意,或者发现支持 -mime 的版本更好,同时想知道 'file' / 'mimetype' 是否有过滤和仅显示可执行文件的选项。
    【解决方案7】:

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

    mdfind 'kMDItemContentType=public.unix-executable'

    至少它有效!

    【讨论】:

    • 很高兴了解 OSX 上的 mdfind。请注意,您的命令会报告 整个系统 的 Unix 可执行文件。 mdfind -onlyin . 'kMDItemContentType=public.unix-executable' 将结果限制在当前目录的子树中。次要兴趣点:显然不支持仅将搜索限制在特定目录(没有子文件夹)。 符号链接 到可执行文件显然不包括在内。奇怪的是,一旦mdfind 发现一个可执行文件,随后删除可执行位被拾取。
    • 我想我发现了 Spotlight 如何检测/取消检测可执行 Unix 文件的错误;我已经向 Apple 以及 openradar.me/20162683 提交了一个错误。我鼓励您 - 以及其他对此功能感兴趣的人 - 也可以在 bugreport.apple.com@ 的错误处提交错误
    • (抱歉评论乱七八糟;希望他们现在是正确的)mdfind -onlyin . 'kMDItemContentType=public.unix-executable' 的行为就像find . -type f -perm +111 -print 一样。也就是说,它会查找设置了 any 可执行位的文件,这可能会产生 false positives (尽管这在实践中可能不是问题) - 真正只查找可执行文件当前用户 使用 BSD 查找,请参阅 @gniourf_gniourf 的答案。使用基于find 的解决方案的优势在于,如果需要,您还可以找到可执行文件的符号链接(选项-L),而mdfind 似乎无法做到。
    • @mklement0 我的回答避开了 装饰 - 试图把重点放在家里 - 但是是的,你几乎永远不会使用这种“不加修饰的”形式。另一种选择 - 不确定它是否出现 - good old globbing.. ls /Applications/**/*(*) 在你的(我的?)zsh shell
    • 感谢方便的zsh 提示 - 不知道; (似乎您可以或者匹配可执行文件(*符号链接(@),但不能同时匹配两者,对吧?)。至于您的原始观点:让我重申:find . -type f -perm +a=x 将执行您的 mdfind 命令执行的操作,同时提供更大的灵活性。您甚至可以将其重新表述为符合 POSIX 标准。
    【解决方案8】:

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

    我对 mac 了解不多,但我认为“mdfind 'kMDItemContentType=public.unix-executable'”可能会错过解释脚本等内容

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

    find . -type f -perm +111 -print
    

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

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

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

    【讨论】:

      【解决方案9】:

      我遇到了同样的问题,答案在 dmenu source code:为此目的而制作的 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)
      

      【讨论】:

        【解决方案10】:

        因此,如果您真的想查找可执行文件类型(例如脚本、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,它基本上为你捆绑了那个小测试,所以如果你找到它,你可以缩短命令行。但是这种方式更灵活,因为您可以轻松地将 == 测试替换为 =~ 测试,并使用它来检查更复杂的属性,例如可执行纯文本文件或文件命令返回的任何其他信息。


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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-19
          • 2018-11-25
          • 1970-01-01
          相关资源
          最近更新 更多