Vim

范围

范围 (Ranges) 其实很好理解,但很多 VIM 用户的理解不到位。

  • 很多命令都可以加一个数字,用于指明操作范围
  • 范围可以是一个行号,用于指定某一行
  • 范围也可以是一对通过 ,; 分割的行号
  • 大部分命令,默认只作用于当前行
  • 只有 :write:global 是默认作用于所有行的

范围的使用是十分直观的。以下为一些例子(其中,:d:delete 的缩写):

命令 操作的行
:d 当前行
:.d 当前行
:1d 第一行
:$d 最后一行
:1,$d 所有行
:%d 所有行(这是1,$ 的语法糖)
:.,5d 当前行至第 5 行
:,5d 同样是当前行至第 5 行
:,+3d 当前行及接下来的 3 行
:1,+3d 第一行至当前行再加 3 行
:,-3d 当前行及向上的 3 行(VIM 会弹出提示信息,因为这是一个保留的范围)
:3,'xdelete 第三行至标注 为 x 的那一行
:/^foo/,$delete 当前行以下,以字符 "foo" 开头的那一行至结尾
:/^foo/+1,$delete 当前行以下,以字符 "foo" 开头的那一行的下一行至结尾

需要注意的是,; 也可以用于表示范围。区别在于,a,bb 是以当前行作为参考的。而 a;bb 是以 a 行作为参考的。举个例子,现在你的光标在第 5 行。这时 :1,+1d 会删除第 1 行至第 6 行,而 :1;+1d 会删除第 1 行和第 2 行。

如果你想设置多个寻找条件,只需要在条件前加上 /,比如:

:/foo//bar//quux/d

这就会删除当前行之后的某一行。定位方式是,先在当前行之后寻找第一个包含 "foo" 字符的那一行,然后在找到的这一行之后寻找第一个包含 "bar" 字符的那一行,然后再在找到的这一行之后寻找第一个包含 "quux" 的那一行。删除的就是最后找到的这一行。

有时,VIM 会在命令前自动添加范围。举个例子,如果你先通过 V 命令进入行选取模式,选中一些行后按下 : 进入命令模式,这时候你会发现 VIM 自动添加了 ' 范围。这表示,接下来的命令会使用之前选取的行号作为范围。但如果后续命令不支持范围,VIM 就会报错。为了避免这样的情况发生,有些人会设置这样的按键映射::vnoremap foo :command,组合键 Ctrl + u 可以清除当前命令行中的内容。

另一个例子是在普通模式中按下 !!,命令行中会出现 :.!。如果这时你如果输入一个外部命令,那么当前行的内容就会被这个外部命令的输出替换。你也可以通过命令 :?^$?+1,/^$/-1!ls 把当前段落的内容替换成外部命令 ls 的输出,原理是向前和向后各搜索一个空白行,删除这两个空白行之间的内容,并将外部命令 ls 的输出放到这两个空白行之间。

请参阅以下两个命令来获取更多帮助:

:h cmdline-ranges
:h 10.3