如何在目录树中递归地查找和替换所有出现的字符串?

Ton*_*ony 46 grep replace sed find

使用grep和sed,如何替换所有出现的:

a.example.com
Run Code Online (Sandbox Code Playgroud)

b.example.com
Run Code Online (Sandbox Code Playgroud)

/home/user/目录树下的文本文件中,递归地查找并替换子目录中所有文件中的所有实例.

veh*_*zzz 76

试试这个:

find /home/user/ -type f | xargs sed -i  's/a\.example\.com/b.example.com/g'
Run Code Online (Sandbox Code Playgroud)

如果你想忽略点目录

find . \( ! -regex '.*/\..*' \) -type f | xargs sed -i 's/a\.example\.com/b.example.com/g'
Run Code Online (Sandbox Code Playgroud)

  • 根据http://stackoverflow.com/a/1583282/477451,分别在`find`和`xargs`命令中使用`-print0`和`-0`是个好主意. (6认同)

小智 28

试试这个:

grep -rl 'SearchString' ./ | xargs sed -i 's/REPLACESTRING/WITHTHIS/g'
Run Code Online (Sandbox Code Playgroud)

grep -rl将递归搜索SEARCHSTRING目录中的./并将使用替换字符串sed.

例如:

更换名称TOMJERRY使用搜索字符串作为SWATKATS目录CARTOONNETWORK

grep -rl 'SWATKATS' CARTOONNETWORK/ | xargs sed -i 's/TOM/JERRY/g'
Run Code Online (Sandbox Code Playgroud)

这将替换TOM为找到字符串的JERRY所有文件和子目录.CARTOONNETWORKSWATKATS


mok*_*gio 14

在 macOS 上,所有答案都不适合我。我发现这是由于与 GNU 相比,macOS 和其他 BSD 系统的工作方式存在差异sed

特别是 BSDsed 采用该-i选项,但需要备份后缀(但允许使用空后缀)

grep来自这个答案的版本。

grep -rl 'foo' ./ | LC_ALL=C xargs sed -i '' 's/foo/bar/g'
Run Code Online (Sandbox Code Playgroud)

find来自这个答案的版本。

find . \( ! -regex '.*/\..*' \) -type f | LC_ALL=C xargs sed -i '' 's/foo/bar/g'
Run Code Online (Sandbox Code Playgroud)

.如果您位于 Git 存储库中,请不要省略正则表达式来忽略文件夹。我意识到这一点很艰难!

LC_ALL=C选项是为了避免获取sed: RE error: illegal byte sequenceifsed发现不是有效 UTF-8 字符的字节序列。这是 BSD 和 GNU 之间的另一个区别。根据您正在处理的文件类型,您可能不需要它。

由于某种我不清楚的原因,该grep版本发现的出现次数比该版本多find,这就是我建议使用grep.


Tim*_*olf 6

我知道这是一个非常古老的问题,但是......

  1. @vehomzzz 的回答使用findxargs问题明确grepsed仅在何时说明。

  2. @EmployedRussian和@BrooksMoses试图说这是一个DUPawksed,但它不是-再次,问题明确表示,grepsed

所以这是我的解决方案,假设您使用 Bash 作为 shell:

OLDIFS=$IFS
IFS=$'\n'
for f in `grep -rl a.example.com .` # Use -irl instead of -rl for case insensitive search
do
    sed -i 's/a\.example\.com/b.example.com/g' $f # Use /gi instead of /g for case insensitive search
done
IFS=$OLDIFS
Run Code Online (Sandbox Code Playgroud)

如果您使用不同的 shell,例如 Unix SHell,请告诉我,我会尝试找到语法调整。

PS:这是一个单行:

OLDIFS=$IFS;IFS=$'\n';for f in `grep -rl a.example.com .`;do sed -i 's/a\.example\.com/b.example.com/g' $f;done;IFS=$OLDIFS
Run Code Online (Sandbox Code Playgroud)

资料来源:


Yah*_*r M 5

对我来说,下一个命令有效:

find /path/to/dir -name "file.txt" | xargs sed -i 's/string_to_replace/new_string/g'
Run Code Online (Sandbox Code Playgroud)

如果字符串包含斜杠“path/to/dir”,则可以将其替换为另一个字符来分隔,例如“@”而不是“/”。

例如: 's@string/to/replace@new/string@g'


小智 5

我们可以尝试使用更强大的 ripgrep 作为

rg "BYE_BYE_TEXT" ./ --files-with-matches | xargs sed -i "s/BYE_BYE_TEXT/WELCOME_TEXT/g"
Run Code Online (Sandbox Code Playgroud)

因为 ripgrep 擅长查找,而 sed 擅长替换。