如何正确确定 GNU 查找的 -or 运算符的范围?如何找到可执行文件的符号链接?

How to properly scope the -or operator for GNU find? How do I find symlinks to executable files?

我正在我的 shell 脚本中创建一个如下所示的函数:

getcmds()
{
    # find all executable files/symlinks in $(searchdirs) that start with 'upvoter-'
    searchdirs | xargs -i find {} -name 'upvoter-*' -type f -or -type l -maxdepth 1 -perm +111
}

当我从脚本中的另一个位置 运行 这个函数时,我得到了一大堆 不是 upvoter- 开头的输出。我最终将范围缩小到 find 是这样解释我的查询的事实:

find everything that's a file and starts with upvoter-, OR is an executable symlink at the top-level directory

我查看了 find man page 以尝试找到解决我的问题的方法。我注意到 find 支持括号,所以我尝试了这个:

find {} -name 'upvoter-*' -type f -or \( -type l \) -maxdepth 1 -perm +111

还有这个:

find {} -name 'upvoter-*' \( -type f -or -type l \) -maxdepth 1 -perm +111

不幸的是,它们都不起作用。我该怎么做才能解决这个问题?

谢谢。

(GNU) find 条件中的条款由 -and(隐式)连接,除非您用 -or 覆盖它。所以,你的最后一个 find 应该有效:

… |
xargs -i find {} -name 'upvoter-*' \( -type f -or -type l \) -maxdepth 1 -perm +111

在命名目录下,它将查找名称以 upvoter- 开头的 fl 类型的文件(文件或符号链接) and1 and 的最大深度,至少具有通用执行权限。它不会找到具有 750455 或其他一些奇怪权限的文件,但它会找到 755711511 或其他类似权限。对于符号链接,如果它不查找符号链接末尾的文件权限而不是符号链接本身的权限,那将是令人惊讶的。当没有指定其他操作时,末尾有一个隐式 -print

请注意,POSIX find 仅支持 -a-o for and and or分别。

补充 和@muru 的 helfpul 评论:

  • 您问题中的 last 命令命令 应该 根据 优先级:

    • find 隐式组合 tests 例如 -typeactions 例如 -print-and(逻辑与;符合 POSIX 的形式是 -a )。
      • 相比之下,-maxdepth 是一个 选项 ,它 不是 位置并且始终适用于 整个命令。
      • 有关 find 术语和概念的概述,请参阅我的
    • 您的 last 解决方案尝试正确地使用括号来更改隐含的计算优先级以实现所需的逻辑(-or 的优先级低于 -and)。
      • 相比之下,第一个解决方案尝试-or \( -type l \)中的括号对优先级完全没有影响,因为它们包含一个单个 仅测试(而定义的优先级仅对 多个 操作数重要)。
      • 请注意如何将 () 引用为 \(\) 以保护它们免受 shell; '('')' 也可以。
  • 但是,-perm 测试可能不会按照您的意愿执行:如所写,它测试符号链接 他们自己 是可执行的,而不是他们的目标。鉴于符号链接总是 标记为可执行文件,无论它们的目标是否是,您最终都会匹配 any 符号链接,即使它没有t 引用可执行文件。

    • 要解决这个问题,使用 -L 选项 ,这使得 find-perm 等测试应用于 target 符号链接。
      • 但是请注意,有一个副作用:使用 -L,当 find 遇到指向 目录 的符号链接时,它会下降到该目录(即,它也处理符号链接的目标目录),默认情况下不会发生。

考虑到上述情况,有点讽刺的是,括号的需要完全消失了,因为 \( -type f -or -type l \) 可以只用 -type f 替换,因为 -L 现在确保符号链接 目标的 类型已测试:

注:
- 我从以下命令中删除了 {} 以仅关注 find 命令。如果没有文件名参数,GNU find 隐式操作当前目录(隐含 .); BSD find,相比之下 需要 一个文件名参数。
- 此外,/111 而不是 +111 被用作权限掩码,因为 + 语法在不久前已被弃用,实际上 已被删除 GNU find 4.5.12.
- 最后,-maxdepth 1 被放置在第一个位置元素 之前 (测试 -name)不仅是为了更清晰的概念(如所述 -maxdepth,因为它是一个 选项 ,始终适用于 entire 命令),但也会抑制 GNU find 的最新版本否则会出现的警告问题。

find -L -maxdepth 1 -name 'upvoter-*' -type f -perm /111

关于您的命令的其他想法:

  • -perm /111 (-perm +111) 应用 any-specified-bit-set 逻辑即,它测试是否为 [=83 设置了可执行位=]任意安全主体;符号模式等价物是 -perm /a=x
    • 如前所述,+ 语法在 GNU find v4.5.12 中被弃用并被删除。
    • BSDfind,相比之下,继续支持+,遗憾的是没有具有此功能的单个命令将适用于 GNU find 4.5.12 或更高版本的两种实现。
    • 无论如何,此功能非标准(不符合POSIX)。
  • 如果您只想匹配设置了 all 执行位的文件,请使用前缀 --perm -111-perm -a=x
  • 或者,如果您想测试文件是否可由 you 执行,请使用 -executable 测试(GNU find 扩展名)。
    • 此外,-executable "takes into account access control lists and other permissions artefacts which the -perm test ignores."(来自 man find)。

最后,GNU xargs-i 选项被弃用;手册建议改用 -I {}