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结尾的g
expression式告诉sed在一行(而不是第一个)上replace多个副本。 -print
find是一个方便的显示哪些文件被匹配。 所有这些都取决于系统上这些工具的确切版本。
如果你的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>
会一次处理多个包含空间的文件名称,每个批处理加载一个解释器。 快多了。
已经给出了使用find和sed的答案
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中对文本文件进行操作几乎没有什么是不可能的。