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

Posted

技术标签:

【中文标题】如何在目录树中递归查找和替换所有出现的字符串? [复制]【英文标题】:How to find and replace all occurrences of a string recursively in a directory tree? [duplicate] 【发布时间】:2010-12-07 19:06:15 【问题描述】:

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

a.example.com

b.example.com

/home/user/ 目录树下的文本文件中递归查找并替换子目录中所有文件中的所有匹配项。

【问题讨论】:

【参考方案1】:

试试这个:

find /home/user/ -type f | xargs sed -i  's/a\.example\.com/b.example.com/g'

如果您想忽略点目录

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

编辑:搜索表达式中的转义点

【讨论】:

这会替换 /home/user 目录下每个文件中的字符串吗?包括子目录? 是的,虽然你应该在 find 之后指定某种模式 -name 'pattern' “某种模式”是什么意思? -name 'pattern' 这样的模式 - 其中“模式”可能类似于“域列表*” - 缩小搜索范围的东西。 根据***.com/a/1583282/477451,最好分别在findxargs 命令上使用-print0-0【参考方案2】:

试试这个:

grep -rl 'SearchString' ./ | xargs sed -i 's/REPLACESTRING/WITHTHIS/g'

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

例如:

使用SWATKATS 目录CARTOONNETWORK 中的搜索字符串将名称TOM 替换为JERRY

grep -rl 'SWATKATS' CARTOONNETWORK/ | xargs sed -i 's/TOM/JERRY/g'

这会将CARTOONNETWORK 下所有文件和子目录中的TOM 替换为JERRY,只要它找到字符串SWATKATS

【讨论】:

谢谢你的回答,以及如何写其他文件以免出错? l 标志在 -rl 中的作用是什么?因为没有它就无法工作:) -l 打印包含与模式匹配的文本的每个文件的路径。【参考方案3】:

在 macOS 上,没有一个答案对我有用。我发现这是由于 sed 在 macOS 和其他 BSD 系统上的工作方式与 GNU 相比存在差异。

特别是 BSD sed takes the -i option but requires a suffix for the backup (but an empty suffix is permitted)

grep 来自 this answer 的版本。

grep -rl 'foo' ./ | LC_ALL=C xargs sed -i '' 's/foo/bar/g'

find 来自this answer 的版本。

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

如果您在 Git 存储库中,请不要忽略正则表达式以忽略 . 文件夹。我意识到这很难!

LC_ALL=C 选项是 avoid getting sed: RE error: illegal byte sequence if sed finds a byte sequence that is not a valid UTF-8 character。这是 BSD 和 GNU 之间的另一个区别。根据您处理的文件类型,您可能不需要它。

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

【讨论】:

【参考方案4】:

我知道这是一个很老的问题,但是......

    @vehomzzz 的答案仅在问题明确指出 grepsed 时使用 findxargs

    @EmployedRussian 和 @***sMoses 试图说这是 awksed 的重复,但它不是 - 再次,问题明确表示 grepsed 只有 em>.

所以这是我的解决方案,假设你使用 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

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

P.S.:这是一个单行:

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

来源:

Bash: Iterating over lines in a variable

grep(1) - Linux man page

Official Grep Manual

sed(1) - Linux man page

Official sed Manual

【讨论】:

Sed 支持使用替代字符分隔符,例如 %,这在 URL 中并不常见,因此您不必转义所有斜杠。 @dragon788 我不知道,但是我并没有逃避正斜杠。我正在逃避经期。句点是任何字符的正则表达式特殊字符,因此必须对其进行转义以专门匹配域名中的句点。【参考方案5】:

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

find /path/to/dir -name "file.txt" | xargs sed -i 's/string_to_replace/new_string/g'

如果字符串包含斜杠'path/to/dir',则可以用另一个字符替换以分隔,例如'@'而不是'/'。

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

【讨论】:

【参考方案6】:

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

rg "BYE_BYE_TEXT" ./ --files-with-matches | xargs sed -i "s/BYE_BYE_TEXT/WELCOME_TEXT/g"

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

【讨论】:

是否有一个选项也可以在 Windows 下进行这项工作(如果您想知道,请使用 git bash)? rg 一直使用反斜杠,sed 不喜欢这样(我猜,因为在我的情况下没有一个与转义码匹配,所以大部分都省略了它们)并且失败并返回 No such file ordirectoy。我可以 sed 将反斜杠改为斜杠,但rg 选项通常会使事情变得更容易。现在我使用rg "inpattern" ./ --files-with-matches | sed "s|\\\|/|g" | xargs sed -i -b "s/inpattern/outpattern/g" - (-b/binary 模式来保持你的行尾不变)。【参考方案7】:

试试这个命令:

/home/user/ directory - find ./ -type f \
-exec sed -i -e 's/a.example.com/b.example.com/g'  \;

【讨论】:

你好。请不要只转储代码作为答案。解释您在做什么,以便用户了解如何解决问题。干杯。【参考方案8】:

比这简单得多。

for i in `find *` ; do sed -i -- 's/search string/target string/g' $i; done

find i => 将遍历文件夹和子文件夹中的所有文件。

sed -i => 将替换文件中的相关字符串(如果存在)。

【讨论】:

【参考方案9】:

下面的命令将递归搜索名称与搜索模式匹配的所有文件并替换字符串:

find /path/to/searchdir/ -name "serachpatter" -type f | xargs sed -i 's/stringone/StrIngTwo/g'

如果你想限制递归的深度,你也可以设置限制:

find /path/to/searchdir/ -name "serachpatter" -type f -maxdepth 4 -mindepth 2 | xargs sed -i 's/stringone/StrIngTwo/g'

【讨论】:

查找 /path/to/searchdir/ -name "serachpatter" -type f -maxdepth 4 -mindepth 2 | xargs sed -i 's/stringone/StrIngTwo/g' 以后,请编辑您的答案,而不是在其下方发表评论。另外,请适当格式化代码;不要在代码中使用粗体格式的文本。

以上是关于如何在目录树中递归查找和替换所有出现的字符串? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Java实验项目三——递归实现字符串查找和替换操作

使用grep和sed递归查找和替换所有文件中的字符串[重复]

批量替换多个文件里边的字符串

递归查找和替换文件中的字符串,为受影响的文件创建备份

使用递归 DFS 在二叉树中查找节点

十五:查找二叉树中所有路径