关于shell:Bash – 使用find命令排除子目录

Bash - Excluding subdirectories using the find command

本问题已经有最佳答案,请猛点这里访问。

我正在使用find命令获取某些文件所在文件夹的列表。但是,由于某些子目录的权限拒绝错误,我想排除某个子目录名。我已经尝试了我在这里找到的这些解决方案:

1
2
3
find /path/to/folders -path"*/noDuplicates" -prune -type f -name"fileName.txt"

find /path/to/folders ! -path"*/noDuplicates" -type f -name"fileName.txt"

以及这些命令的一些变体(例如路径名的变体)。在第一种情况下,它根本找不到文件夹,在第二种情况下,我再次得到错误,所以我猜它仍然试图访问这个目录。有人知道我做错了什么,或者有人对此有不同的解决方案吗?


为了补充Olim的有用答案,并解决OP对需要-o的困惑:

  • -prune与每个findprimary(操作或测试,在gnu语言中)一样,返回一个布尔值,在-prune的情况下,该布尔值始终是true
  • 如果没有显式的操作符,primaries就隐式地与-a(-and)联系在一起,就像它的兄弟-o(-or执行短路布尔逻辑一样。
  • -a的优先级高于-o

有关所有find概念的摘要,请参阅https://stackoverflow.com/a/29592349/45375

因此,公认的答案,

1
find . -path ./ignored_directory -prune -o -name fileName.txt -print

等价于(括号用于使计算优先级显式化):

1
2
3
find . \( -path ./ignored_directory -a -prune \) \
       -o \
       \( -name fileName.txt -a -print \)

由于短路适用,因此评估如下:

  • 匹配./ignored_directory的输入路径会导致-prune被评估;由于-prune总是返回true的值,因此短路会阻止-o运算符的右侧被评估;实际上,不会发生任何事情(忽略输入路径)。
  • 输入路径与./ignored_directory不匹配,由于短路,立即再次在-o的右侧继续评估:
    • 只有当输入路径的文件名部分与fileName.txt匹配时,才是-print主要的评估值;实际上,只打印文件名与fileName.txt匹配的输入路径。

编辑:尽管我最初在这里声明了什么,但这里的-o的右侧需要-print;如果没有它,隐含的-print将应用于整个表达式,因此也打印用于左侧匹配;背景信息见下文。

相比之下,让我们考虑一下错误地不使用-o会做什么:

1
find . -path ./ignored_directory -prune -name fileName.txt -print

这相当于:

1
find . -path ./ignored_directory -a -prune -a -name fileName.txt -a -print

这将只打印修剪后的路径(也与-name过滤器匹配),因为-name-print主项(隐式)与逻辑ands相连;在这种特定情况下,由于./ignored_directory不能与fileName.txt匹配,因此不打印任何内容,但如果-path的参数是一个全局参数,则可以获得输出。

关于find隐式使用-print的一个词:

POSIX要求,如果find命令的表达式作为一个整体不包含

  • 产出型初级产品,如-print本身
  • 执行某物的初选,如-exec-ok
  • (给出的示例primary对于find的posix规范是详尽的,但是实际的实现(如gnu find和bsd find)添加了其他的,例如生成-print0primary的输出和执行-execdirprimary的输出)

-print隐式应用,如同该表达式被指定为:

\( expression \) -print

这很方便,因为它允许您编写诸如find .之类的命令,而不需要附加-print

但是,在某些情况下,需要一个明确的-print,这里的情况也是这样:

假设我们在接受的答案末尾没有指定-print

1
find . -path ./ignored_directory -prune -o -name fileName.txt

由于表达式中现在没有生成或执行primary的输出,因此计算结果为:

1
find . \( -path ./ignored_directory -prune -o -name fileName.txt \) -print

这将无法按预期工作,因为如果整个括号表达式的计算结果为true(在本例中错误地包括修剪过的目录),它将打印路径。

相反,通过将-print显式附加到-o分支,只有当-o表达式的右侧的值为真时,才会打印路径;使用括号使逻辑更清晰:

1
find . -path ./ignored_directory -prune -o \( -name fileName.txt -print \)

相反,如果左侧为真,则只执行-prune,不产生输出(由于整体表达式包含-print,因此不隐式应用-print)。


编辑(添加了行为规范详细信息)

删除find中所有拒绝权限的目录

使用GNUSED。

规范行为详细信息-在此解决方案中,我们希望:

  • 排除不可读的目录内容(删减它们),
  • 避免"拒绝许可"错误来自不可读的目录,
  • 保留其他错误和返回状态,但是
  • 处理所有文件(即使是不可读的文件,如果我们可以读取它们的名称)
  • 基本设计模式为:

    1
    find ...  \( -readable -o -prune \) ...

    例子

    1
    find /var/log/ \( -readable -o -prune \) -name"*.1"

    谢谢mklement0


    根据我之前的评论,这适用于我的Debian:

    1
    find . -path ./ignored_directory -prune -o -name fileName.txt -print

    1
    find /path/to/folder -path"*/ignored_directory" -prune -o -name fileName.txt -print

    1
    find /path/to/folder -name fileName.txt -not -path"*/ignored_directory/*"

    分歧在这里争论得很好。


    问题在于find计算传递给-path选项的表达式的方式。相反,您应该尝试如下操作:

    1
    find /path/to/folders ! -path"*noDuplicates*" -type f -name"fileName.txt"