7 bash shell sed pipe find-util
我有这个find命令:
find . -type f -not -path '**/.git/**' -not -path '**/node_modules/**' | xargs sed -i '' s/typescript-library-skeleton/xxx/g;
Run Code Online (Sandbox Code Playgroud)
由于某种原因,它给了我这些警告/错误:
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
Run Code Online (Sandbox Code Playgroud)
我甚至尝试过使用:
-not -path '**/.git/objects/**'
Run Code Online (Sandbox Code Playgroud)
得到了同样的事情.有人知道为什么查找在.git目录中搜索?看起来很奇怪.
为什么在.git目录中搜索?
GNU find很聪明,并支持对一个简单实现的几个优化:
-size +512b -name '*.txt'并首先检查名称,因为查询大小将需要第二个系统调用.-type d或用于递归.(-B -or -C) -and -A以便如果检查成本相同且没有副作用,-A将首先评估,希望在1次测试后拒绝该文件而不是2.然而,它还不够聪明,意识到这-not -path '*/.git/*'意味着如果你找到一个目录,.git那么你甚至不需要递归到它,因为里面的所有文件都无法匹配.
相反,它尽职地递归,找到每个文件并将其与模式匹配,就好像它是一个黑盒子一样.
要明确告诉它完全跳过目录,您可以改为使用-prune.请参见如何在find中排除目录.命令
更高效和更正确的方法是避免默认-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 '{}' +
Run Code Online (Sandbox Code Playgroud)
请注意以下几点:
-prune用来告诉find甚至没有递减不需要的目录,而不是-not -path ...告诉它在找到它们之后丢弃这些目录中的名字.-prune小号之前的-type f,所以我们能够匹配目录修剪.-print.这很重要,因为默认情况下-print有效地有一组括号:如果给出明确的操作,则find ...表现得像find '(' ... ')' -print,不喜欢find ... -print,不行.xargs仅使用-0支持NUL分隔输入的参数,以及侧面的-print0操作find来生成NUL分隔的名称列表.NUL是唯一不能出现在任意文件路径中的字符(是的,可以存在换行符) - 因此是唯一可以安全地用于分隔路径的字符.(如果不保证-0扩展名xargs和-print0扩展名find可用,请-exec sed -i '' ... {} +改用).