【发布时间】:2010-10-03 00:57:21
【问题描述】:
我正在尝试在所有与 grep 匹配的文件中搜索和替换字符串:
grep -n 'foo' * 会给我以下形式的输出:
[filename]:[line number]:[text]
对于 grep 返回的每个文件,我想通过将 foo 替换为 bar 来修改文件。
【问题讨论】:
我正在尝试在所有与 grep 匹配的文件中搜索和替换字符串:
grep -n 'foo' * 会给我以下形式的输出:
[filename]:[line number]:[text]
对于 grep 返回的每个文件,我想通过将 foo 替换为 bar 来修改文件。
【问题讨论】:
根据您提供的示例,这似乎是您想要的:
sed -i 's/foo/bar/g' *
它不是递归的(它不会下降到子目录中)。对于在整个树中替换选定文件的一个很好的解决方案,我会使用 find:
find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
*.html 是文件必须匹配的表达式,-i 之后的 .bak 会复制原始文件,扩展名为 .bak(可以是您喜欢的任何扩展名)和 @987654326 @ 在 sed 表达式的末尾告诉 sed 替换一行上的多个副本(而不是仅替换第一个)。要查找的-print 可以方便地显示正在匹配的文件。这一切都取决于您系统上这些工具的确切版本。
【讨论】:
find 命令提供一个目录,例如 find . -name '*.html' 或 find directoryname/ -name '*'。
sed -ie 's/foo/bar/g' *
你的意思是在所有被grep匹配的文件中搜索并替换一个字符串?
perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`
编辑
因为这似乎是一个相当受欢迎的问题,所以我想更新一下。
现在我主要使用ack-grep,因为它对用户更友好。所以上面的命令是:
perl -p -i -e 's/old/new/g' `ack -l searchpattern`
要处理文件名中的空格,您可以运行:
ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'
您可以使用ack-grep 做更多事情。假设您只想将搜索限制为 HTML 文件:
ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'
如果空白不是问题,它会更短:
perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files
【讨论】:
Can't open Untitled: No such file or directory, <> line 5 在尝试“Untitled Folder/file.txt”时。
如果你的sed(1) 有一个-i 选项,那么像这样使用它:
for i in *; do
sed -i 's/foo/bar/' $i
done
如果没有,根据您要使用的语言,以下几种方法会有所不同:
ruby -i.bak -pe 'sub(%r{foo}, 'bar')' *
perl -pi.bak -e 's/foo/bar/' *
【讨论】:
for i in *; do ... 是多余的,sed 可以将文件列表作为参数。
for i in *; do; sed -i 's/foo/bar/g' "$i"; done
我喜欢并使用了上述解决方案或在数千个文件中进行系统范围的搜索和替换:
find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;
我假设使用 '*.htm?'它搜索并查找 .htm 和 .html 文件,而不是 .html。
我将 .bak 替换为系统更广泛使用的波浪号 (~),以便更轻松地清理备份文件。
【讨论】:
这可以使用 grep 而无需使用 perl 或 find。
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
【讨论】:
-i 不适用于其他操作系统。在 ubuntu 上为我工作。
xargs 手册页(在 Ubuntu 上)说 -i 已被弃用,而是使用 -I。所以,我们应该说:grep -rli 'old-word' * | xargs -I filepath sed -i 's/old-word/new-word/g' filepath
find . -type f -print0 | xargs -0 <sed/perl/ruby cmd> 将一次处理多个包含空格的文件名,每批加载一个解释器。更快。
【讨论】:
已经给出了使用 find 和 sed
的答案find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
可能是标准答案。或者您可以使用perl -pi -e s/foo/bar/g' 代替sed 命令。
对于大多数快速使用,您可能会发现命令 rpl 更容易记住。这是替换(foo -> bar),递归地在当前目录中的所有文件上:
rpl -R foo bar .
它在大多数 Linux 发行版上默认不可用,但可以快速安装(apt-get install rpl 或类似的)。
但是,对于涉及正则表达式和反向替换、文件重命名以及搜索和替换的更棘手的工作,我所知道的最通用和最强大的工具是 repren,一个我为一些更棘手的重命名和重构任务编写了一个小的 Python 脚本。您可能更喜欢它的原因是:
Check the README 示例。
【讨论】:
这实际上比看起来容易。
grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
简单易懂。如果你很好地掌握了 find、grep、xargs、sed 和 awk,那么在 bash 中操作文本文件几乎没有什么是不可能的:)
【讨论】:
2022 年答案。
https://github.com/BurntSushi/ripgrep/blob/master/FAQ.md#how-can-i-search-and-replace-with-ripgrep
rg foo --files-with-matches | xargs sed -i 's/foo/bar/g'
将在 ripgrep 找到 foo 模式的文件中用 'bar' 替换所有 'foo' 实例。 sed 的 -i 标志表明您正在就地编辑文件,并且 s/foo/bar/g 表示您正在执行模式 foo 对 bar 的替换,并且您正在全局执行此替换(所有出现的每个文件中的模式)。
【讨论】: