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

时间:2016-02-20 06:14:56

标签: linux bash shell unix posix

我在我的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 正在解释我的查询这样的事实:

  

查找所有文件并以upvoter-开头,或者是顶级目录中的可执行符号链接

我查看了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

不幸的是,他们都没有工作。我该怎么做才能解决这个问题?

感谢。

2 个答案:

答案 0 :(得分:5)

补充Jonathan Leffler's helpful answer和@ muru的helfpul评论:

  • 问题中的 last 命令命令应按优先级 工作:

    • find隐式将测试(例如-type操作,例如-print-and合并(逻辑AND) ;符合POSIX的表单是-a)。
      • 相比之下,-maxdepth选项位置,始终适用于整个命令。
      • 有关find术语和概念的概述,请参阅我的this answer
    • 您的 last 解决方案尝试正确使用括号更改隐含的评估优先级以实现所需的逻辑(-or优先级低于-and)。
      • 相比之下,第一次解决方案尝试中的括号-or \( -type l \)根本不会影响优先级,因为它们只包含单个测试(而依据定义的优先级仅对多个操作数)有用。
      • 请注意()如何被引用为\(\)以保护他们免受 shell 的解释; '('')'也可以使用。
  • 但是, -perm测试可能不会达到您想要的效果:正如所写,它会测试符号链接本身是否可执行,而不是他们的目标。鉴于符号链接总是标记为可执行文件,无论其目标是什么,您最终都会匹配任何符号链接,即使它没有引用可执行文件

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

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

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

find

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

  • find -L -maxdepth 1 -name 'upvoter-*' -type f -perm /111 -perm /111)应用任何 - 指定位设置逻辑,即测试是否为任何设置了可执行位安全负责人;符号模式等价物是-perm +111
    • 如前所述,-perm /a=x语法不久前已弃用,并已在GNU + v4.5.12中删除。
    • 相反,
    • BSD find继续支持find,遗憾的是,没有任何一个具有此功能的命令可以使用使用GNU + 4.5.12或更高版本的两种实现。
    • 无论如何,此功能非标准(不符合POSIX标准)。
  • 如果您只想匹配所有执行位的文件,请使用前缀find--perm -111
  • 或者,如果您想测试文件是否可由执行,请使用-perm -a=x测试(GNU -executable扩展名)。
    • 此外,find“会考虑访问控制列表以及-perm测试忽略的其他权限假象。” (来自-executable)。

最后,不推荐使用GNU man find的{​​{1}}选项;手册建议改为使用xargs

答案 1 :(得分:4)

条件(GNU)find中的条件(隐式)由-and连接,除非您使用-or覆盖它。因此,您的上一个find应该有效:

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

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

请注意,POSIX find仅支持以及-a-o