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
(给出的示例初选对于find
的POSIX 规范而言是详尽无遗的,但是诸如GNU find
和BSD find
之类的实际实现添加了其他内容,例如输出-生产-print0
primary,执行-execdir
primary)
-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】:
编辑(添加行为规范细节)
在查找中修剪所有权限被拒绝的目录
使用 gnufind。
规范行为细节 - 在这个解决方案中我们想要:
-
排除不可读的目录内容(修剪它们),
避免来自不可读目录的“权限被拒绝”错误,
保留其他错误并返回状态,但是
处理所有文件(即使是不可读的文件,如果我们可以读取它们的名称)
基本的设计模式是:
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 - 使用查找命令排除子目录[重复]的主要内容,如果未能解决你的问题,请参考以下文章