【问题标题】:Why is my `find` command giving me errors relating to ignored directories?为什么我的 `find` 命令会给出与忽略目录相关的错误?
【发布时间】:2018-10-18 17:26:03
【问题描述】:

我有这个查找命令:

find . -type f  -not -path '**/.git/**' -not -path '**/node_modules/**'  | xargs sed -i '' s/typescript-library-skeleton/xxx/g;

出于某种原因,它给了我这些警告/错误:

find: ./.git/objects/3c: No such file or directory
find: ./.git/objects/3f: No such file or directory
find: ./.git/objects/41: No such file or directory

我什至尝试过使用:

-not -path '**/.git/objects/**'

得到了同样的结果。有人知道为什么 find 在 .git 目录中搜索吗?看起来很奇怪。

【问题讨论】:

  • -name .git -prune 会更有效率。使用-not -path ... 告诉find 忽略匹配该值的文件,但它不会告诉它避免递归目录。
  • 查看stackoverflow.com/questions/37047322/… 以获取默认-print 和显式-print 行为不同的问题示例,回复:为什么find ...find ... -print 实际上并不相同它涉及否定逻辑。

标签: bash shell sed pipe find-util


【解决方案1】:

为什么 find 在 .git 目录中搜索?

GNU find 很聪明,支持 several optimizations 而不是简单的实现:

  • 它可以翻转-size +512b -name '*.txt' 的顺序并首先检查名称,因为查询大小将需要第二个系统调用。
  • 它可以计算一个目录的硬链接以确定子目录的数量,当它全部看到时,它不再需要检查它们是否有-type d或递归。
  • 它甚至可以重写(-B -or -C) -and -A,这样如果检查成本同样高且没有副作用,-A 将首先被评估,希望在 1 次而不是 2 次测试后拒绝文件。

然而,它还不够聪明地意识到-not -path '*/.git/*' 意味着如果你找到一个目录.git,那么你甚至不需要递归到它,因为里面的所有文件都会匹配失败。

相反,它尽职尽责地递归,找到每个文件并将其与模式匹配,就好像它是一个黑盒子一样。

要明确告诉它完全跳过一个目录,您可以改用-prune。见How to exclude a directory in find . command

【讨论】:

  • 虽然它更直接地作为 OP 的“为什么”问题的答案,但我不确定这 是否 是一个完整的解决方案。试图遵循这一点的人可以轻松地将原始问题的代码修改为find . -type f -name .git -prune -name node_modules -prune | xargs ...,这根本不起作用(-prunes 将永远不匹配,因为之前的-type f;条件是ands ,而不是 ors,并且默认的 -print 规则具有不正确的推断优先级)。需要更多指导来描述如何正确申请 -prune.
  • @CharlesDuffy 如果问题是“我如何排除目录”,那么可以说它应该作为副本关闭
  • 好电话——我同意链接到一个演示实践的问题就足够了。
【解决方案2】:

更有效和更正确的方法是避免默认的-print 操作,将-not -path ... 更改为-prune,并确保xargs 仅用于NUL 分隔的输入:

find . -name .git -prune -o \
       -name node_modules -prune -o \
       -type f -print0 | xargs -0 sed -i '' s/typescript-library-skeleton/xxx/g '{}' +

注意以下几点:

  • 我们使用-prune 告诉find 甚至不递归下不需要的目录,而不是-not -path ... 告诉它在找到这些目录后丢弃这些目录中的名称。李>
  • 我们将-prunes 放在 -type f 之前,因此我们能够匹配目录以进行修剪。
  • 我们有一个显式操作,不依赖于默认的-print。这很重要,因为默认的-print 实际上有一组括号:find ... 的行为类似于find '(' ... ')' -print,而不是find ... -print,如果给出明确的操作则不会。
  • 我们仅使用xargs 与启用NUL 分隔输入的-0 参数和find 端的-print0 操作生成一个以NUL 分隔的名称列表。 NUL 是唯一不能出现在任意文件路径中的字符(是的,可以出现换行符)——因此 only 字符可以安全地用于分隔路径。 (如果不能保证-0 扩展至xargs-print0 扩展至find 可用,请改用-exec sed -i '' ... {} +)。

【讨论】:

  • 见仁见智,但我确实同意将这些上移看起来更好。
  • 我用过:find . -type f -name .git -prune -o -name node_modules -prune -o | xargs sed -i '' s/typescript-library-skeleton/waldo/g; 得到了这个错误no expression after -o
  • 是的,-o 的意思是“或”。你需要在右边有一个动作(如果左边的事情不正确,则要执行)。您是否有理由不使用我给出的答案?第三个要点明确告诉您不要依赖默认的-print 操作,我在对该问题的评论中给出的相关问题的链接详细解释了这种依赖如何导致错误。
  • 我对这场辩论充满热情。 xargs 允许并行文件搜索和命令执行,因此使用昂贵的检查或冷目录可以显着提升。此外,xargs 通常允许并行化多个命令调用,这极大地改进了当今多核系统上的独立 CPU 绑定任务
猜你喜欢
  • 2015-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-11
  • 1970-01-01
  • 1970-01-01
  • 2015-12-03
  • 2012-10-05
相关资源
最近更新 更多