递归目录中的快速字符串替换

for*_*rin 0 recursive replace

如何使用带有空格单引号的递归目录和文件名进行快速文本替换?最好使用标准的 UNIX 工具,或者一个众所周知的包。

find对于许多文件,使用速度非常慢,因为它为每个文件生成一个新进程,因此我正在寻找一种将目录遍历和字符串替换集成为一个操作的方法。

慢搜索:

find . -name '*.txt'  -exec grep foo {} \;
Run Code Online (Sandbox Code Playgroud)

快速搜索:

grep -lr --include=*.txt foo
Run Code Online (Sandbox Code Playgroud)

缓慢替换:

find . -name '*.txt' -exec perl -i -pe 's/foo/bar/' {} \;
Run Code Online (Sandbox Code Playgroud)

快速更换:

# Your suggestion here
Run Code Online (Sandbox Code Playgroud)

(这个速度相当快,但是是两次传递并且不处理空格。)

perl -p -i -e 's/foo/bar/g' `grep -lr --include=*.txt foo`
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 5

您只想使用:

 find . -name '*.txt'  -exec cmd {} \;
Run Code Online (Sandbox Code Playgroud)

那些cmd只能接受一个参数的 s 的形式。情况并非如此grep。与grep

 find . -name '*.txt'  -exec grep foo /dev/null {} +
Run Code Online (Sandbox Code Playgroud)

(或-H与 GNU 一起使用grep)。更多关于递归grep vs find / -type f -exec grep {} \; 哪个更有效/更快?

现在更换,那是一样的,perl -pi可以采取不止一个论点:

 find . -name '*.txt' -type f -exec perl -pi -e s/foo/bar/g {} +
Run Code Online (Sandbox Code Playgroud)

现在,无论文件是否包含,都会重写文件foo。相反,您可能想要(假设 GNUgrep和/xargs或兼容):

 find . -name '*.txt' -type f -exec grep -l --null foo {} + |
   xargs -r0 perl -pi -e s/foo/bar/g
Run Code Online (Sandbox Code Playgroud)

或者:

 grep -lr --null --include='*.txt' foo . |
   xargs -r0 perl -pi -e s/foo/bar/g
Run Code Online (Sandbox Code Playgroud)

所以只有包含的文件foo被重写。


顺便说一句,--include=*.txt--include作为另一个 GNU 扩展)是一个 shell glob,所以应该被引用。例如,如果--include=foo.txt当前目录中有一个文件被调用,shell 会--include=*.txt在调用grep. 如果没有,对于许多 shell,您会收到关于 glob 无法匹配任何文件的错误。

所以你会想要 grep --include='*.txt'