在Vim中搜索和替换所有项目文件


117

我正在寻找在Vim中所有项目文件中进行搜索和替换(带有确认)的最佳方法。“项目文件”是指当前目录中的文件,其中有些文件不必打开。

一种方法是简单地打开当前目录中的所有文件:

:args ./**

然后搜索并替换所有打开的文件:

:argdo %s/Search/Replace/gce

但是,当我这样做时,Vim的内存使用量从几十MB跃升至2 GB以上,这对我不起作用。

我还安装了EasyGrep插件,但是它几乎永远无法工作-找不到所有出现的事件,或者只是挂起,直到我按为止CtrlC。到目前为止,我首选的完成此任务的方法是ack-grep搜索词,使用它的quickfix窗口打开包含该词但之前未打开的任何文件,最后是:bufdo %s/Search/Replace/gce

我正在寻找一个可以用于此目的的好插件,或者正在寻找一个比我现在使用的命令/命令序列更容易的命令/命令序列。


1
@Cascabel由于您写了此评论,所以这里有一个vi.stackexchange.com网站。
Flimm

Answers:


27

Greplace对我来说效果很好。

github 上还有一个病原体就绪版本


8
安装它后,我看到了其他类似:Gsearch:Gbuffersearch存在的命令,但是当我键入时,:Greplace我得到了Not an editor command: Greplace
拉蒙·塔亚格

根据文档,语法为::Gsearch [<grep-option(s)>] [[<pattern>] [<filename(s)>]] 因此您可以使用以下方式进行递归搜索::Gsearch -r pattern dir/
vitorbal 2013年

我讨厌Greplace的事情是,如果该模式位于文件名中,则Greplace会失败,因为您最终也将其替换为文件名。
丹尼尔(Daniel)

2
6年后这里并没有什么异常,但是与3年前的最新更新(github.com/yegappan/greplace)相比,此插件已严重过时。我可能会查看Sid的内置解决方案:stackoverflow.com/a/38004355/2224331(不是我在另一个帐户上,只是一个巧合:P)
SidOfc

99

这里的另一个大选择就是不使用vim:

sed -i 's/pattern/replacement/' <files>

或者,如果您有某种生成文件列表的方式,也许是这样的:

find . -name *.cpp | xargs sed -i 's/pattern/replacement/'
grep -rl 'pattern1' | xargs sed -i 's/pattern2/replacement/'

等等!


谢谢!我真的需要学习这种老式的命令行知识。我认为这是最好的答案。这些正则表达式是perl正则表达式还是vim正则表达式或其他某种正则表达式?
埃里克·约翰逊

2
@EricJohnson:它们是... sed正则表达式,本质上是POSIX.2基本正则表达式,但不完全是正则表达式(在手册页中)-它们使\n换行符和其他一些相似的东西匹配。因此,它们与grep正则表达式几乎相同。
卡斯卡贝尔2012年

sed命令中是否有-i原因?手册页说这是用于指定扩展名,但您似乎并未真正指定扩展名。
davekaro

好的,实际上看起来是's / pattern / replacement /'是扩展名,我想我现在明白了。
davekaro

11
在Mac OS X上,唯一对我find . -type f | LANG=C xargs sed -i '' 's/SEARCH/REPLACE/g'
有用的

74

编辑:使用cfdo命令而不是cdo大大减少将要完成此操作的命令数量(因为cdo在每个元素上cfdo运行命令而在每个文件上运行命令)

感谢最近添加的cdo命令,现在您可以使用grep已安装的任何工具,以两个简单的命令执行此操作。无需额外的插件!:

1. :grep <search term>
2. :cdo %s/<search term>/<replace term>/gc
3. (If you want to save the changes in all files) :cdo update

cdo对指定的快捷方式列表中的每个术语执行给定的命令grep。)

c如果您要替换每个搜索词而无需每次都确认,请删除第二个命令末尾的)


12
另外,您可以添加:cdo update以将更改保存在所有文件中。
哲力

1
但是在修改当前缓冲区时,每次切换到下一个缓冲区之前,它都会暂停以警告未保存。
lfree

1
@谢谢,我已经将其添加到答案中了;@lfree我个人更喜欢确认每个更改,但是您可以c在第二个命令的末尾删除(仅使用g),以进行搜索和替换而无需寻求确认
Sid

1
:cdo%s /搜索词/替换词/ g仅替换第一次出现的内容,但不适用于我的vim中第二次出现的内容
sunxd

3
为了使用update,我必须:cdo %s/<search term>/<replace term>/g | update
gabe

34

我决定使用ack和Perl解决此问题,以便利用功能更强大的完整Perl正则表达式而不是GNU子集。

ack -l 'pattern' | xargs perl -pi -E 's/pattern/replacement/g'

说明

确认

ACK是一个真棒的命令行工具,它是一个组合grepfind以及全Perl的正则表达式(不只是GNU子集)。它使用纯Perl编写,速度快,语法高亮,可在Windows上运行,并且比传统命令行工具对程序员更友好。在Ubuntu上安装sudo apt-get install ack-grep

xargs

Xargs是旧的UNIX命令行工具。它从标准输入读取项目,并执行指定的命令,然后执行为标准输入读取的项目。因此,基本上,由ack生成的文件列表将附加到perl -pi -E 's/pattern/replacemnt/g'命令末尾。

perl -pi

Perl是一种编程语言。-p选项使Perl在您的程序周围创建一个循环,该循环遍历文件名参数。-i选项使Perl在适当位置编辑文件。您可以修改它以创建备份。-E选项使Perl执行指定为程序的一行代码。在我们的例子中,该程序只是Perl regex的替代品。有关Perl命令行选项的更多信息perldoc perlrun。有关Perl的更多信息,请参见http://www.perl.org/


我喜欢这个答案,因为它甚至适用于cygwin的行尾。请注意,它确实在修改的行的末尾添加了一个\ r,但是当使用sed时,它将替换每个换行符,从而使差异无法使用。Perl更加理智,这是一个非常好的搜索和替换代码。谢谢!
安德鲁(Andrew)2012年

@andrew,我不确定您的情况到底出了什么问题。它会帮助您在正则表达式中使用\ R而不是\ n吗?请参见perldoc.perl.org/perlrebackslash.html#Misc中的 \ R部分。另外,请尝试perldoc.perl.org/perlre.html#Regular-Expressions。Perl是一个非常跨平台的平台,我敢肯定您有一种方法可以使结尾的行尾不被破坏。
埃里克·约翰逊

我的正则表达式中没有换行符,这些程序的cygwin版本会在每行修改的末尾自动添加\ r。我特别喜欢perl版本,因为它只会修改匹配的行,而sed会修改所有行,即使它们不匹配正则表达式也是如此。
安德鲁(Andrew)2012年

如果文件路径包含空格怎么办?
shengy 2014年

23

也许这样做:

:noautocmd vim /Search/ **/*
:set hidden
:cfirst
qa
:%s//Replace/gce
:cnf
q
1000@a
:wa

说明:

  • :noautocmd vim /Search/ **/*⇒ 为了提高速度,在cwd的所有子目录中的所有文件中查找模式(vim是的缩写vimgrep),而不会触发autocmds(:noautocmd)。
  • :set hidden ⇒允许修改后的缓冲区不显示在窗口中(可能在您的vimrc中)
  • :cfirst ⇒跳至第一个搜索结果
  • qa ⇒开始将宏记录到寄存器a中
  • :%s//Replace/gce⇒将所有出现的最后一个搜索模式(仍在/Search/当时)替换为Replace
    • 在同一行(g标志)上几次
    • 带有用户确认(c标志)
    • 如果没有找到模式,则没有错误(e标志)
  • :cnf⇒跳转到vim命令创建的列表中的下一个文件
  • q ⇒停止录制宏
  • 1000@a ⇒播放存储在寄存器中的宏1000次
  • :wa ⇒保存所有修改后的缓冲区

*编辑* Vim 8方式:

从Vim 8开始,有一种更好的方法,因为它:cfdo会遍历quickfix列表中的所有文件:

:noautocmd vim /Search/ **/*
:set hidden
:cfdo %s//Replace/gce
:wa

您可能想为我们这些小凡人解释一下。我不清楚您是否每次都需要执行此“序列”操作。我使用生锈的旧Delphi 5可以更快地做到这一点,所以我肯定会丢失一些东西。
Lieven Keersmaekers

1
@Lieven:你是对的,这有点晦涩,没有评论。我将提出一些解释。
Benoit

+1,尽管尽管vim在很多方面为我赢得了胜利,但我认为我会坚持使用PowerGrep。
Lieven Keersmaekers

感谢您的回答和所有命令的解释,我非常感谢。我接受其他答案,因为我更喜欢为此使用插件。
psyho 2011年

考虑到某人提出问题的水平与理解该答案所需的水平之间的差异,我将其标记为低,因为这会引起更多的混乱。
劳埃德·摩尔

22

:args从shell命令填充

可以(在某些操作系统上为1)):args通过shell命令提供文件。

例如,如果您安装了ack 2

:args `ack -l pattern`

会要求ack返回包含“模式”的文件列表,并将它们放在参数列表中。

或者用普通ol'grep我猜是这样的:

:args `grep -lr pattern .`  


然后,您可以:argdo按照OP的描述使用:

:argdo %s/pattern/replacement/gce


:args从快速修复列表填充

还要检查nelstrom对一个相关问题的答案,该问题描述了一个简单的用户定义命令,该命令从当前quickfix列表中填充了arglist。这个伟大的工程与许多命令和插件的输出在quickfix列表结束(:vimgrep:Ack3:Ggrep4)。

然后可以执行以下操作来执行项目范围内的搜索:

:vimgrep /pattern/ **/*
:Qargs 
:argdo %s/findme/replacement/gc

在哪里:Qargs是对用户定义的命令的调用,该命令从快速修复列表中填充了arglist。

随后的讨论中,您还将找到指向简单插件的链接,这些插件可使此工作流程简化为2或3个命令。

链接

  1. :h {arglist} -vimdoc.sourceforge.net/htmldoc/editing.html# {arglist }
  2. ACK - betterthangrep.com/
  3. ack.vim - github.com/mileszs/ack.vim
  4. 逃犯 - github.com/tpope/vim-fugitive

1
argdo在出现写入问题的第一个文件后停止
frankster 2015年


5

如果您不介意引入外部依赖关系,那么我会酿造一个插件ctrlsf.vim(取决于ackag)来完成这项工作。

它可以格式化和显示来自ack / ag的搜索结果,并将结果缓冲区中的更改同步到磁盘上的实际文件。

也许下面的演示解释了更多

ctrlsf_edit_demo


3
1. :grep <search term> (or whatever you use to populate the quickfix window)
2. :cfdo %s/<search term>/<replace term>/g | update

步骤1用所需的项填充快速修复列表。在这种情况下,它与您要通过更改的搜索字词一起传播grep

cfdo在quickfix列表中的每个文件上运行以下命令。键入:help cfdo了解详情。

s/<search term>/<replace term>/g替换每个术语。/g表示替换文件中的所有匹配项。

| update 每次替换后保存文件。

我根据此答案及其评论将其拼凑在一起,但由于它全部集中在一个位置,因此觉得它应有自己的答案。


对我而言,在NeoVim上,需要在上面的第2行中进行一些修改:2. :cfdo %s/<search term>/<replace term>/g | update如果不使用%,则仅替换模式的第一个匹配项。
Kareem Ergawy

谢谢卡里姆。我也更新了答案,因为它也%s适用于常规vim。
Kyle Heironimus

0

基本上,我希望在单个命令中进行替换,更重要的是在vim本身中

根据@Jefromi回答,我创建了一个键盘快捷方式,我已在我的.vimrc文件中设置了该快捷方式,如下所示

nmap <leader>r :!grep -r -l  * \| xargs sed -i -e 's///g'

现在从vim中,通过leader + r的笔触,我将命令加载到vim中,如下所示进行编辑,

:!grep -r -l <find> <file pattern> | xargs sed -i -e 's/<find>/<replace>/g'

因此,我用单个命令进行替换,更重要的是在vim本身内


而我实际上使用的是ag而不是grep
deepak 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.