Bash - 使用查找命令排除子目录[重复]

Posted

技术标签:

【中文标题】Bash - 使用查找命令排除子目录[重复]【英文标题】:Bash - Excluding subdirectories using the find command [duplicate] 【发布时间】:2015-06-27 06:48:40 【问题描述】:

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

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

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

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

【问题讨论】:

从***.com/questions/4210042/… ,在-prune 之后添加一个-o 选项。你试过吗? 感谢您的建议!我确实试过了,如果你想排除多个名称/路径,显然它的意思是“或”。 【参考方案1】:

补充olivm's helpful answer 并解决OP 对需要-o 的困惑:

-prune,就像每个 find 主要(用 GNU 说的动作或测试)一样,返回一个 Boolean,并且在-prune。 如果没有显式的运算符,主元素与 -a (-and) 隐式连接,这与它的兄弟 -o (-or) 一样执行短路布尔逻辑。李> -a 的优先级高于 -o

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

因此,接受的答案

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

等价于(括号用于明确计算优先级):

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 匹配的输入路径。

编辑:尽管我最初在这里声明,-print 需要在 -o 的右侧;没有它,implied -print 将适用于 整个 表达式,因此 打印 left-hand边赛;有关背景信息,请参见下文。


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

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

这相当于:

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

这将打印修剪路径(也匹配-name过滤器),因为-name-print原色(隐式)与逻辑与; 在这种特定情况下,由于./ignored_directory 不能同时匹配fileName.txt,所以会打印nothing,但如果-path 的参数是一个glob,它 有可能得到输出。


关于find隐式使用-print

POSIX mandates 如果find 命令的表达式作为一个整体不包含任何一个

产生输出原色,例如-print本身 执行某些东西的主要元素,例如-exec-ok (给出的示例初选对于findPOSIX 规范而言是详尽无遗的,但是诸如GNU find 和BSD find 之类的实际实现添加了其他内容,例如输出-生产-print0primary,执行-execdirprimary)

-print 被应用隐式,就好像表达式被指定为:

\( expression \) -print

这很方便,因为它允许你写find .等命令,而不需要附加-print

但是,在某些情况下需要明确的-print,如下所示:

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

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

由于表达式中现在没有产生输出或执行的主节点,因此它被评估为:

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

这不会按预期工作,因为如果 整个 括号表达式的计算结果为真,它将打印路径,在这种情况下错误地包括修剪的目录。

相比之下,通过将-print 显式附加到-o 分支,仅当-o 表达式的右侧计算结果为true 时才会打印路径;使用括号使逻辑更清晰:

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

相比之下,如果左侧为真,则仅执行 -prune,这不会产生任何输出(并且由于 overall 表达式包含 -print-print 是未隐式应用)。

【讨论】:

【参考方案2】:

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

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

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

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

这些差异被很好地讨论了here

【讨论】:

第一个成功了!谢谢!!显然我不明白 -o 正确.. -o 标志意味着如果表达式的第二部分(-name 条件和-print 操作)仅在第一部分(路径条件)为假时执行。 【参考方案3】:

编辑(添加行为规范细节)

在查找中修剪所有权限被拒绝的目录

使用 gnufi​​nd。

规范行为细节 - 在这个解决方案中我们想要:

    排除不可读的目录内容(修剪它们), 避免来自不可读目录的“权限被拒绝”错误, 保留其他错误并返回状态,但是 处理所有文件(即使是不可读的文件,如果我们可以读取它们的名称)

基本的设计模式是:

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

例子

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

\谢谢mklement0

【讨论】:

@mklement0,再次感谢您!现在我很高兴! (r1) 感谢-print 中的-o 技巧! (r2) 我在答案中添加了“预期的行为规范详细信息”。作为一般结论find 通常对于简单的事情非常棒,但对于“棘手”的问题“棘手”...... 感谢您鼓励我这样做,但您具体指的是哪些信息? find args 的一些公理化翻译... a -o b = (a orelse b) print ; a -o b print = a orelse (b print) -- 有一天我会做一个 find-dsl :) 好的,谢谢;我在答案中添加了一个部分;如果您认为需要改进,请告诉我。【参考方案4】:

问题在于find 评估您传递给-path 选项的表达式的方式。 相反,您应该尝试以下方法:

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

【讨论】:

谢谢!不幸的是,这仍然给出了同样的错误:( 那么也许您可以通过重定向标准错误消息来“隐藏”错误:find /path/to/folders ! -path "*noDuplicates*" -type f -name "fileName.txt" 2>/dev/null 也已经尝试过这样做,但它仍然会失败(在 shell 脚本中使用命令时)。我在测试目录上测试了这个命令,没有导致子目录的问题,比它工作正常,所以我很确定这是问题所在。不过非常感谢您的帮助!

以上是关于Bash - 使用查找命令排除子目录[重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用查找时排除文件夹[重复]

在查找命令中排除子路径[重复]

linux find命令查找当前目录下7天前的文件但排除所有目录

使用 Bash 查找和复制文件 [重复]

查找文件,原地重命名 unix bash

python学习- 打印最常用的10条linux命令和查找目录下重复的文件