在Vim中,如何对多个文件重复多次替换?

In Vim, how do you repeat multiple substitutions for multiple files?

我有 10 个文件,每个文件包含 'apple' 和 'red'。我想将所有 10 个文件的 'apple' 更改为 'pear',并将 'red' 更改为 'green'。

我目前的方法是在每个文件中键入此查找和替换命令 :%s/apple/pear/g(对于红色到绿色也是如此)。如何保存这两个替换并将它们应用于 10 个文件。更一般地说,我如何更有效地做到这一点?

我是 vim 的新手,不确定是否要查看命令历史记录或 vim 寄存器或其他内容。

您可以使用 :argdo:bufdo 等命令对多个文件重复相同的 Ex 命令。 (参见 :help :argdo。)

例如,您可以通过将 10 个文件作为参数传递给 Vim 来打开它们。如果都是*.txt个文件,你可以使用:

$ vim *.txt

然后你可以使用:argdo对所有作为参数得到的文件Vim重复操作:

:argdo %s/apple/pear/eg | update

请注意,我在操作末尾添加了一个 | update,以便在执行替换后为每个文件保存文件。这很重要,否则 :argdo 会在移动到下一个文件之前出错。 (参见:help :update,它类似于:w,但仅在有修改时才保存。|是Vim中Ex命令的命令分隔符。)

使用 | update 的另一种方法是使用 :set hidden,它允许您在继续下一个文件之前开始编辑另一个文件。 (请参阅 :help 'hidden'。)您稍后可以使用 :wall 在完成所有修改后写入所有文件。

最后,我将一个额外的 /e 标志传递给替换,以防止它在没有要替换的匹配项时生成错误。 (参见 :help :s_e。)

您还可以使用 | 作为分隔符来链接多个命令(例如替换命令)。例如:

:set hidden
:argdo %s/apple/pear/eg | %s/red/green/eg
:wall

基础知识

Vim 没有随项目范围的查找和替换一起提供。归结为执行以下步骤:

  • 创建您希望处理的文件列表
  • 运行 您对列表中每个文件的命令

换人

您可以 运行 使用 | 一个接一个地执行多个命令。

例子

:s/apple/pear/ | s/red/green/

由于您更新了这些文件,因此最好也 :write:update 文件

:s/apple/pear/ | s/red/green/ | update

替换标志:

  • 对“全局”使用 g 或每行进行多次替换
  • 使用e 来抑制错误。我们需要这个,因为文件可能有 apple 但没有 red 例如

:s 采用类似于 1,3 的范围来处理第 1 行到第 3 行。$ 表示最后一行编号。整个文件是 1,$。使用 % 作为 shorthand 用于 1,$

:%s/apple/pear/ge | %s/red/green/ge | update

想法:

  • 可能想在您的模式周围使用 \<\>。例如。 red 模式,因为 red 可以用不同的词表示,例如 predicate
  • 可能要考虑大小写

参数列表

如果您从Vim开始使用您希望处理的文件列表,那么这些文件已经在参数列表中

$ vim file*.txt

您可以在 vim 通过 :args:argadd 启动后提供参数。例如:args file*.txt

使用:args查看参数列表

使用 :argdo {cmd} 到 运行 你的命令,{cmd} 参数列表中的所有文件

Quickfix 列表

您通常希望在一组文件中搜索某个模式,然后对这些匹配项进行替换。 Vim的:vimgrep & :grep搜索文件并将这些位置放入Quickfix List

:vimgrep /apple\|red/ **/*.txt

您可以使用 :copen:clist 查看 quickfix 列表。

使用 :cdo {cmd}/:cfdo {cmd} 到 运行 命令,{cmd},在 quickfix 列表中的每个 position/file

:cfdo %s/apple/pear/ge | %s/red/green/ge | update
:cdo s/apple/pear/e | s/apple/pear/e | update

升级:grep

:grep 将使用 'grepprg' & 'grepformat' 来执行和读取类似 grep 的程序的输出(在 linux 上默认使用)。这通常比 :vimgrep 更快,但要以使用不同的正则表达式语法为代价。

而不是使用 grep 作为你的 'grepprg',你可以使用像 ripgrep or ag the silver searcher 这样的东西,它们通常比普通的 grep.

更快

ripgrep 的配置选项示例:

set grepprg=rg\ --vimgrep
set grepformat=%f:%l:%c:%m

现在您可以:grep 'apple\|red'填充快速修复列表

如果您愿意,您甚至可以通过 running :grep in a subshell

更进一步

其他列表?!?

Vim 还有其他列表,例如:缓冲区、window、选项卡、位置列表。它们有一个关联的“do”命令::bufdo:windo:tabdo:ldo

废除的:Subvert

虽然跨文件进行此类替换不需要插件,但了解 Tim Pope 的 vim-abolish 插件可能会很方便。特别是如果你有很多这样的替换 and/or 有大小写问题。废除的:Subvert/:S命令可以将你的替换命令减少到1个命令

:%S/{apple,red}/{pear,green}/gw

这将转换 apple -> pearred -> green 因为它们在大括号内的位置。

使用 :Subvertw 标志仅替换单词。 Subvert 也将处理案例

Vim演员表

这里有一些 Vimcasts 相关的剧集:

TL;DR

搜索 :vimgrep 和 运行 您的替换 :cfdo

:vimgrep /apple\/red/ *.txt
:cfdo %s/apple/pear/ge | %s/red/green/ge | update

需要更多帮助

使用 Vim 的帮助系统阅读更多内容

   :h argument-list
   :h :argdo
   :h :args
   :h quickfix.txt
   :h :cdo
   :h :cfdo
   :h :vimgrep
   :h :grep
   :h 'grepprg'
   :h 'grepformat'

quickfix-reflector 允许您在 quickfix 中编辑结果并将这些编辑应用回原始文件。

  1. 像往常一样使用 :grep 在您的项目中搜索匹配项 (:grep apple -R .) -- 或者您想要填充 quickfix 的任何方法。
  2. 编辑快速修复。 (:%s/apple/pear/ge | %s/red/green/ge)
  3. 保存快速修复缓冲区。 (:w)
  4. 现在您的所有文件都已修改(或者 quickfix 在无法更新的行旁边显示错误)。

通常情况下,quickfix 不是 'modifiable',但 quickfix-reflector 会修改该设置并添加一个挂钩以在保存时传播更改。有几个替代插件提供类似的功能,这对您的工作流程来说是一个很大的改变!