如何在Vim中的目录中递归搜索和替换?

时间:2010-01-21 21:37:00

标签: search vim recursion

我发现了Vim的替代命令......

:%s/replaceme/replacement/gi

和vimgrep ......

:vimgrep  /findme/gj  project/**/*.rb

有没有办法将它们组合起来,以便在目录下的所有文件中进行替换?

7 个答案:

答案 0 :(得分:62)

即使我是Vim用户,我通常会使用findsed来做这类事情。 sed的正则表达式语法类似于Vim(它们都是ed的后代),但不完全相同。使用GNU sed,您还可以使用-i进行就地编辑(通常sed将修改后的版本发送到stdout)。

例如:

find project -name '*.rb' -type f -exec sed -i -e 's/regex/replacement/g' -- {} +

一块一块:

  • project =在“项目”树中搜索
  • -name '*.rb' =表示名称与'* .rb'
  • 匹配的内容
  • -type f =并且是常规文件(不是目录,管道,符号链接等)
  • -exec sed =使用以下参数运行sed
    • -i =使用就地编辑
    • -e 's/regex/replacement/g' =执行“替换”命令(与Vim的:s几乎相同,但请注意缺少% - 这是sed中的默认值< / LI>
    • -- =标志结束,文件名从此处开始
    • {} =这告诉find它找到的文件名应放在sed的命令行上
    • + =这告诉find -exec操作已完成,我们希望将参数分组为尽可能少的sed次调用(通常比每个文件名运行一次)。要按文件名运行一次,您可以使用\;代替+

这是GNU sedfind的一般解决方案。在特殊情况下,这可以缩短一点。例如,如果您知道您的名称模式与任何目录都不匹配,则可以省略-type f。如果您知道所有文件都不以-开头,则可以省略--Here's an answer I posted to another question with more details on passing filenames found with find to other commands.

答案 1 :(得分:54)

argsargdo应该做您需要的事情,例如

:args spec/javascripts/**/*.* 
:argdo %s/foo/bar/g

请参阅this page

答案 2 :(得分:7)

您可以运行vimgrep然后记录一个宏,该宏转到vimgrep输出中的每一行并执行替换,如下所示:(不要输入#comments!)

:set autowrite                  #automatically save the file when we change buffers
:vimgrep /pattern/ ./**/files  
qa                              #start recording macro in register a
:s/pattern/replace/g            #replace on the current line
:cnext                          #go to next matching line
q                               #stop recording
10000@a                          #repeat the macro 10000 times, or until stopped by 
                                #an "error" such as reaching the end of the list
:set noautowrite

我还没有测试过,所以可能需要稍微调整一下 - 测试一些你不介意先搞砸的文件。

这个优于sed的优势在于Vim正则表达式更强大,您可以将c选项添加到:s以验证每次替换。

修改: 我修改了原来的帖子,因为它错了。我正在使用:1vimgrep来查找每个文件中的第一个匹配项,但我误读了文档 - 它只找到所有文件中的一个匹配项。

答案 3 :(得分:5)

一种方法是打开要在其上运行替换的所有文件(或任何命令),然后运行:bufdo <cmd>,它将在所有打开的缓冲区上运行<cmd>

答案 4 :(得分:4)

有一个插件努力做到这一点:Vimgrep Replace

哦,等等......还有其他人:Global ReplaceEasyGrep

对于无插件解决方案,如果你可以将argdo输出到参数列表(可以使用vimgrep设置),args可能有帮助,但我可以'似乎弄清楚了细节。如果有人接受了这个想法并对其进行了改进,我会感到高兴......所以就是这样。

第一个插件背后的基本思想(我猜其他插件......)首先使用vimgrep,然后使用:cnext循环匹配并在每个插件上应用替换命令线。实现这一目标的功能可以小到足以将其放入.vimrc中。 (也许你可以从插件的来源中解除一个?)

(我想hgimenez可能会找到一个解决方案,但它是否合适可能取决于要处理的文件数量......无论如何插件都应该没问题。)

答案 5 :(得分:2)

回答结合vimgrep和替代品的原始问题:

:vimgrep /pattern/ ./**/files              # results go to quickfix list
:set autowrite                             # auto-save when changing buffers
:silent! cdo %s/replaceme/replacement/gic  # cdo draws filenames from quickfix list
:set noautowrite

如果您不想确认每次替换,请忽略c中的gic(在这种情况下,您也可以按照@的建议使用findsed LaurenceGonsalves)。

答案 6 :(得分:0)

这适用于少量文件。

vim`找到。 -type f`

:bufdo%s / pattern / replacement / gec |更新