Linux命令行全局搜索和替换

时间:2009-01-22 22:54:16

标签: linux sed awk grep

我正在尝试搜索并替换linux机器上grep匹配的所有文件中的字符串。我有一些我想做的事情,但我不确定如何最好地将它们串在一起。

grep -n 'foo' *会以下列形式提供输出:

[filename]:[line number]:[text]

对于grep返回的每个文件,我想用“bar”替换“foo”并将结果写回文件。有没有一个好方法呢?也许是一条奇特的管道?

8 个答案:

答案 0 :(得分:108)

根据您提供的示例,这似乎是您想要的:

sed -i 's/foo/bar/g' *

它不是递归的(它不会下降到子目录中)。为了一个很好的解决方案替换整个树中的选定文件我会使用find:

find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

*.html是文件必须匹配的表达式,.bak复制原始文件后的-i,扩展名为.bak(可以是任何扩展名)喜欢)和sed表达式末尾的g告诉sed在一行(而不是只有第一行)上替换多个副本。要查找的-print可以方便地显示哪些文件正在匹配。所有这些都取决于系统上这些工具的确切版本。

答案 1 :(得分:70)

您的意思是搜索并替换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

答案 2 :(得分:13)

如果您的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/' *

答案 3 :(得分:6)

我喜欢并使用上述解决方案或系统范围的搜索,并在数千个文件中替换:

find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;

我假设'* .htm?'而不是.html它搜索并找到.htm和.html文件。

我用更多系统使用的代字号(〜)替换.bak,以便更轻松地清理备份文件。

答案 4 :(得分:4)

这可以使用grep而无需使用perl或find。

grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @

答案 5 :(得分:3)

find . -type f -print0 | xargs -0 <sed/perl/ruby cmd>将一次处理多个空格包含的文件名,每批加载一个解释器。快得多。

答案 6 :(得分:1)

已经给出了使用查找 sed

的答案

find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

可能是标准答案。或者您可以使用perl -pi -e s/foo/bar/g'代替sed命令。

对于大多数快速用途,您可能会发现命令 rpl 更容易记住。这是替换(foo - &gt; bar),递归地对当前目录中的所有文件:

rpl -R foo bar .

默认情况下,它在大多数Linux发行版中都不可用,但可以快速安装(apt-get install rpl或类似)。

然而,对于涉及正则表达式和反向替换,或文件重命名以及搜索和替换的更艰难的工作,我所知道的最通用和最强大的工具是 repren ,我写了一些小的Python脚本,用于一些棘手的重命名和重构任务。您可能更喜欢它的原因是:

  • 支持重命名文件以及搜索和替换文件内容(包括在目录之间移动文件和创建新的父目录)。
  • 在您提交执行搜索和替换之前查看更改。
  • 支持带有后置替换,整个单词,不区分大小写和保留大小写的正则表达式(替换foo - &gt; bar,Foo - &gt; Bar,FOO - &gt; BAR)模式。
  • 使用多个替换项,包括交换(foo - &gt; bar和bar - &gt; foo)或非唯一替换项集(foo - &gt; bar,f - &gt; x)。

Check the README示例。

答案 7 :(得分:1)

这实际上比看起来容易。

grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
  • grep通过你的树(-R)进行递归并打印文件名(-l),从当前目录开始(./)
  • 通过管道传输给xargs,它一次处理一个(-n 1),并在shell命令(sh -c)中使用%作为占位符(-I%)
  • 在shell命令中
  • ,首先打印文件名(ls%;)
  • 然后sed执行内联操作(-i),foo的替换(&#39; s /&#39;)和bar(foo / bar),全局(/ g)文件(再次表示) by%)

容易腻。如果你很好地掌握了find,grep,xargs,sed和awk,那么在bash中对文本文件操作几乎没有什么是不可能的:)