感谢@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,但使用不兼容的语法:
- 因此,如果您的代码必须可移植,请避免这些扩展。
- 以下示例演示了各种以文件为中心的问题的可移植答案。
以文件为中心的命令示例
注意:
- 以下示例符合 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 中也称为 actions 和 tests)与-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 一起使用,但这不是一个好主意。