Linux命令行全局search和replace

我试图在Linux机器上search和replacegrep匹配的所有文件中的string。 我已经得到了一些我想要做的事情,但是我不确定如何将它们串在一起。

grep -n 'foo' *会以下面的forms输出:

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

对于由grep返回的每个文件,我想用“bar”replace“foo”并将结果写回到文件中。 有没有一个很好的方法来做到这一点? 也许是一个奇特的pipe道?

你的意思是search并replace所有grep匹配的文件中的string?

 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来做更多的事情。 假设您只想将search限制在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 

这似乎是你想要的,根据你给的例子:

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

它不是recursion的(它不会下到子目录中)。 为了一个很好的解决schemereplace整个树中选定的文件,我会使用find:

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

*.html是文件必须匹配的expression式, -i在原始文件的副本之后创build一个.bak扩展名(它可以是任何扩展名)以及sed结尾的gexpression式告诉sed在一行(而不是第一个)上replace多个副本。 -printfind是一个方便的显示哪些文件被匹配。 所有这些都取决于系统上这些工具的确切版本。

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

我喜欢和使用上述解决scheme或系统范围的search和replace成千上万的文件:

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

我假设用'* .htm?' 而不是.html它search并find.htm和.html文件。

我用更广泛的代字号(〜)来replace.bak文件,以便清理备份文件。

这工作使用grep而不需要使用perl或find。

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

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

已经给出了使用findsed的答案

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

可能是标准答案。 或者你可以使用perl -pi -es/foo/bar/g'而不是sed命令。

对于大多数快速使用,您可能会发现命令rpl更容易记住。 这里是replace(foo – >酒吧),recursion当前目录中的所有文件:

rpl -R foo bar .

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

但是,对于涉及正则expression式和后置replace,文件重命名以及searchreplace的更复杂的工作 ,我所知道的最通用和最强大的工具是repren ,一个我为某些人编写的小Python脚本更棘手的重命名和重构任务。 你可能更喜欢它的原因是:

  • 支持重命名文件以及search和replace文件内容(包括在目录之间移动文件和创build新的父目录)。
  • 在承诺执行search和replace之前查看更改。
  • 支持后置replace,全字,不区分大小写,保留大小写的正则expression式(replacefoo – > bar,Foo – > Bar,FOO – > BAR)模式。
  • 可以使用多个replace,包括掉换(foo – > bar和bar – > foo)或非唯一replace(foo – > bar,f – > x)。

检查自述文件的例子。

这实际上比看起来更容易。

 grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %"; 
  • grep通过你的树(-R)recursion,并从当前目录(./)开始打印文件名(-l)
  • (-n 1),并在shell命令(sh -c)中使用%作为占位符(-I%),
  • 在shell命令中,首先打印文件名(ls%;)
  • 那么sed执行一个内联操作(-i),一个带有bar(foo / bar)的foo的substution('s /'),全局(/ g)的文件(同样用%表示)

十分简单。 如果你对find,grep,xargs,sed和awk有很好的把握,那么在bash中对文本文件进行操作几乎没有什么是不可能的。