Vim搜索替换当前(项目)文件夹中的所有文件


36

关于Vim的一个开放性问题是,是否有一种方法可以在当前项目中执行搜索/替换(如果我使用从其他编辑器继承来的这个概念,请与我一起忍受)。

例如,假设我要在项目文件中搜索方法名称,然后重命名该方法调用的所有实例。

这就是我继续进行Sublime的方式。

在此处输入图片说明

在Vim(可能是MacVim)中如何在不依赖其他程序(例如ack或)的情况下进行此操作sed

Answers:


35

有几种方法可以做到这一点。

内部当前目录

如果要在项目树中执行搜索/替换,可以使用Vim的参数列表

只需打开Vim,然后使用:args命令填充参数列表。您可以传入多个文件名甚至glob。

例如,:args **/*.rb将在当前目录中递归搜索ruby文件。注意,这也类似于使用打开Vim vim **/*.rb。您甚至可以使用shell的find命令通过运行以下命令来获取当前目录中所有文件的列表:

:args `find . -type f`

您可以通过单独运行来查看当前的args列表:args。如果要从列表中添加或删除文件,可以分别使用:argadd:argdelete命令。

对列表满意后,现在就可以使用Vim强大的:argdo命令,该命令为参数列表中的每个文件运行一个命令::argdo %s/search/replace/g

以下是一些搜索提示(基于一些评论):

  1. 如果要搜索“ foo”而不是“ foo_bar”,请使用单词边界。在搜索模式周围使用\<\>构造,如下所示::argdo %s/\<search\>/foobar/g
  2. /c如果您希望Vim在替换搜索词之前要求确认,请使用搜索标志。
  3. /e如果要跳过“未找到模式”错误,请使用搜索标志。
  4. 您还可以在执行搜索后选择保存文件::argdo %s/search/replace/g | update。在这里:update使用,因为它只会在文件更改后保存文件。

打开缓冲区

如果您已经打开了缓冲区要进行搜索/替换,则可以使用:bufdo,它为缓冲区列表(:ls)中的每个文件运行一个命令。

该命令非常类似于:argdo:bufdo %s/search/replace/g

类似:argdo:bufdo,有:windo:tabdo分别的窗口和标签该行为。它们很少使用,但仍然有用。


4
使用该/c标志确认替换可能是一个好主意。
romainl

3
我还建议使用单词边界\<\>周围,search以避免部分单词替换。
tommcdo

1
另一种意见是,默认情况下,vim的工作目录是您启动vim的位置,而不是当前文件的目录。您可以使用将工作目录设置为当前文件:cd %:p:h。其他工作目录选项在vim.wikia.com/wiki/Set_working_directory_to_the_current_file中列出。
studgeek '16

28

假设我们有一个简单的项目结构,如下所示:

在此处输入图片说明

greeting.txt看起来像

在此处输入图片说明

和info / age.txt看起来像

在此处输入图片说明

假设我们要用Bob替换所有出现的Sam。这是我们要做的:

  1. 设置工作目录

    确保Vim的当前工作目录是项目的根目录(此处不会向您展示如何执行此操作)。

  2. 查找包含“ Sam”的文件

    使用Vim的vimgrep命令搜索项目中所有Sam的出现(请注意:以**/*递归方式搜索所有文件)

    :vimgrep /Sam/gj **/*
    

    这将使用Sam的所有实例填充快速修复列表。如果要查看快速修复列表,可以使用Vim命令:copen 在此处输入图片说明

  3. 在所有包含“ Sam”的文件中替换

    现在我们要在quickfix列表中的每个文件中运行Vim的替代命令。我们可以使用:cfdo {cmd}在quickfix列表中每个文件中执行{cmd} 的命令来执行此操作。我们要使用的特定{cmd}是substitutes简称。整行如下所示:

    :cfdo %s/Sam/Bob/g
    

    如果愿意,可以添加c标志以确认所有替换:

    :cfdo %s/Sam/Bob/gc
    
  4. 保存所有文件

    :cfdo update
    

2
我更喜欢这个。这很简单,可以与Ack(或填充QuickFix窗口的任何插件)一起使用。
Zuhaib

1
这是一个很好的答案
Peoplee 2016年

2
正在获得“自上次更改以来没有写过”的信息,cfdo %s/Sam/Bob/g | update为我解决了这一问题
hakunin

@hakunin 如果您尚未设置该hidden选项,我建议:set hidden您使用。
Niko Bellic,

3

尽管不是VIM解决方案,但如果使用的是VI / VIM,则可能会发现使用CLI解决方案更容易。要更改当前目录中的所有文件,请使用perl以下情况:

$ perl -pi -e 's/foo/bar/g' *

如果您也需要在子目录中执行此操作,我通常会perl配合使用find

$ find . -name '*' -print0 | xargs -0 perl -pi -e 's/foo/bar/g'

这样做的好处是,您可以轻松地将列表进一步细化为特定的文件类型。例如,限制为python文件:

$ perl -pi -e 's/foo/bar/g' *.py
$ find . -name '*.py' -print0 | xargs -0 perl -pi -e 's/foo/bar/g'

1

要将短语替换为另一个短语,可以使用Vim Ex模式。

例如(ex是的别名vim -E):

$ ex -s +'bufdo!%s/foo/bar/g' -cxa *.*

在bash / zsh中递归globstar设置(例如,shopt -s globstar):

$ ex -s +'bufdo!%s/foo/bar/g' -cxa **/*.*
$ ex -s +'n **/*.*' +'bufdo!%s/foo/bar/g' -cxa

递归(使用find和忽略诸如文件之类的隐藏.git文件):

$ find . -type f -not -path '*/\.*' -exec ex -s +'bufdo!%s/foo/bar/g' -cxa {} "+"

注意:该:bufdo命令不是POSIX

注意:语法-not -path '*/\.*'用于忽略隐藏的文件(例如.git)。



0

这是使用findex编辑器的shell命令(不使用:bufdo):

find . -name '*.rb' -exec ex +'%s/foo/bar/ge' -V1 -scwq! {} ';'

这将就地*.rb(递归)编辑当前文件夹中的所有文件,并替换foobar

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.