7

我有这个查找命令:

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目录中搜索吗?似乎很奇怪。

4

2 回答 2

7

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

GNUfind很聪明,并且支持对幼稚实现的多种优化:

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

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

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

要明确告诉它完全跳过目录,您可以改用-prune. 请参阅如何在 find 中排除目录。命令

于 2018-05-08T17:47:38.643 回答
6

更有效和更正确的方法是避免默认-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 ...告诉它在找到这些目录后丢弃这些目录中的名称。
  • 我们将 s 放在-prunes之前-type f因此我们能够匹配目录以进行修剪。
  • 我们有一个明确的动作,不依赖于默认值-print。这很重要,因为默认值-print实际上有一组括号:如果给出了明确的操作,则find ...表现得像find '(' ... ')' -print,不像,no 。find ... -print
  • 我们xargs仅使用-0启用 NUL 分隔输入的参数,以及生成 NUL 分隔的名称列表的-print0操作。findNUL 是唯一不能出现在任意文件路径中的字符(是的,可以出现换行符)——因此是唯一可以安全用于分隔路径的字符。(如果不保证-0扩展名xargs-print0扩展名find可用,请-exec sed -i '' ... {} +改用)。
于 2018-05-08T17:24:21.213 回答