0%

【工具】vim入门笔记

Vim 对于每个开发人员都不陌生,这可能是我们接触最多的 Linux 软件。所有类 Unix 的系统(Linux、Mac)都安装了 vim。当我们通过终端操作文本时,vim 或许是我们唯一的选择。

然而,vim 的使用方式和我们所熟悉的可视化编辑器完全不同,它的的快捷键是如此奇怪,不易上手。因此除非兴趣使然,我们很少会主动学习 vim。它的上限够高,下限也足够低,只需要掌握最基本的操作:↑↓←→i<ESC>:wq,就可以覆盖大部分使用场景。那为什么还需要再深入学习 vim 呢?

主要原因是:用较少的学习成本,换来较大的效率提升。Vim 常用的几个快捷键,可以在手指不离开键盘热区的情况下快速定位光标或编辑内容,这些内容的学习成本并不高。如果你开发运维的过程中和 vim 打交道的次数越来越多,掌握这些技巧可以极大的提升开发效率。即使现在没有需求,也可以提前上手这个强大的工具。

为什么写这篇文章

现有的 vim 教程 / 文章大多直接罗列完整的 vim 快捷键列表,让人不知从何下手。我认为应当先掌握最重要的、最高频的快捷键,满足日常开发所需;其他低频使用的快捷键,可以作为一个速查表按需查看,vim 的进阶用法也可以之后再深入研究。

因此,我尝试作为一个 vim 初学者,总结 vim 主要和次要的快捷键,同时提供一些学习 vim 的资源。

注意:在阅读本文时,你随时可以在终端执行 vimtutor,打开一个教程文本文件,尝试某个快捷键或命令。

学习资源

这里顺便再推荐一些可视化学习资源:

术语说明

vim 中有一些术语:

  • mode:标准模式 normal、插入模式 insert、可视模式 visual 等。
  • verb:vim 里执行的操作,比如删除 d、修改 c、拷贝 y、查找 f 等。verb 后面需要跟一个 motion,表示该操作生效的范围。
  • motion:vim 里移动的范围,比如向右一个字母 l、向下一行 j、向右一个单词 w 等。本文中有时候也称其为 “range”。

符号说明

标题的前缀:

  • [M]:移动类,move
  • [E]:编辑类,edit
  • [F]:查找类,find

入门

标准模式 / 插入模式

  • 标准模式(Normal Mode):进入 vim 的默认模式,这个模式下按下任何键不会实际输入到文本中,按下 : 可以执行命令
  • 插入模式(Insert Mode):在标准模式按下 i 进入插入模式,此时可以输入文本;按下 <ESC> 退出插入模式

执行命令::<command>

按下 : 后输入命令,按回车执行。如 :set number 会显示行号。

退出 vim::q / ZZ

  • :q / :quit:退出 vim,不作任何改动
  • :q!:退出 vim,丢弃已有的改动
  • :wq:保存更改(write)并退出(quit)vim
  • ZZ:等同于 :wq,这个快捷键输入比 :wq 更快,注意是大写 Z

保存文件: :w / :w <filename>

  • :w:保存更改
  • :w <filename>:保存到一个新的文件

[M] 基本移动:h / j / k / l

使用 hjkl 而不是 ,这能够避免将手指移出键盘热区再移回来。如果有必要的话,甚至可以禁用方向键,来强制自己使用 hjkl

1
2
3
4
map <Left> <Nop>
map <Right> <Nop>
map <Up> <Nop>
map <Down> <Nop>

[M] 前往第一行 / 最后一行:gg / G

  • gg:前往第一行
  • 1G:同 gg
  • G:前往最后一行

[M] 前往第 n 行:nG:n

  • nG:前往第 n 行。1G 可以前往第一行。如果希望在 vim 中显示行号,可以在标准模式下执行 set number 命令。
  • :n 也可以前往第 n 行,比如 :123前往第 123 行。

[M] 向右移动一个单词:w / e

  • w:向右移动一个单词,光标将落在下一个单词的首字符
  • e:向右移动一个单词,光标将落在当前一个单词的最后一个字符

在这里,一个单词的定义是连续的「数字+字母+下划线」,或者连续的「特殊字符」。比如 hello, world!!! 里包含 hello,world!!! 四个单词。按 w 跳转时,会跳过单词后面的所有空白字符,落在下一个单词的开头。示例:

1
2
3
4
5
6
7
↓ 光标在这里
Hello, world!
↑ 按下 w
↑ 按下 e
Hello, world!
↑ 按两下 w
↑ 按两下 e

类似的还有 W / E,区别在于这两个快捷键对单词的定义是连续的「非空字符」,即以空格作为单词的分界线。比如 hello, world!!! 里,包含 hello,world!!! 两个单词。

[M] 向左移动一个单词:b

b 向左移动到前一个单词的首字符,相当于是 w 的逆操作。b 取 backwards 首字母,「单词」的定义同 w

2b 向左移动两个单词,nb 向左移动 n 个单词。

B 向左移动一个单词,将「空格」作为单词的分隔符(同 WE)。

[M] 移动到前一个单词的末尾:ge

ge 移动到前一个单词的末尾,gE 将空格作为单词的分隔符。

[M] 前往当前行第一个 / 最后一个字符:0 / $ / _ / ^

  • 0:前往第一个字符,可以理解成是第 0 列
  • $:前往最后一个字符
  • _:前往第一个非空字符,这在编写 python 等有缩进的代码时很有用。^ 等价。

[E] 删除字符:x / X

  • x:删除当前字符,等同于 <Delete>
  • X:删除前一个字符

[E] 删除单词:dw

「单词」的定义同 w,单词后面的任意多个空格将被删除。

类似的还有 dW,删除下一个空格前的单词。

[E] 删除当前行:dd

略。

[E] 在当前位置后面插入:a

i 在当前位置前面插入(insert),a 在当前位置后面插入(append)。

[E] 在当前行开始 / 末尾插入:I / A

略。

[E] 在当前行下面 / 上面插入新行:o / O

插入新的空白行。

[E] 改变大小写:~ / gu / gU

  • ~:将光标下的字母改变大小写。3~ 是将光标开始的 3 个字母改变大小写。
  • gu<motion>:指定范围的字母变成小写。比如 guw 是后一个单词全变成小写,guj 是当前整行改成小写。gU 则是改成大写。
  • guu:将当前行的字母改成小写。gUU 是改成大写。
  • guiw:将光标所在的单词改成小写。详见下文

[F] 移动到下一个指定字符:f<target>

ft 移动到下一个 t 出现的位置,f2 移动到下一个 2 出现的位置。f 取 forward 的首字母。

F 类似于 f,向前移动到前一个指定字符。

t 类似于 f,只不过光标会移动到下一个指定字符之前T 类似于 F,只不过光标会移动到前一个指定字符之后t 取 until 的含义。

示例:

1
2
3
4
5
6
7
8
    ↓ 光标在这里
Hello, world!
↑ fo
↑ fr
↑ Fh
to
Th
解释

[E] 撤销 / 重做:u / <Ctrl> + r

  • u:撤销(undo)
  • <Ctrl> + r:重做(redo)

中场休息:vim 的一些模式

重复 n 次操作:n<action>

Vim 中几乎所有操作都可以通过一个 n 前缀来重复 n 次:

  • 5h 向左移动 5 个字符。5j 向下移动 5 行。2w 向右移动两个单词,等同于按两次 w
  • 2x 删除两个字符,2X 向左删除两个字符。
  • 3fa 在当前行查找第 3 次出现的 a,等同于按 3 次 fa
  • 2u 撤销前两步操作,等同于按两次 u2<Ctrl> + r 重做被撤销的两步操作,等同于按两次 <Ctrl> + r

操作任意范围:<verb><motion>

我们以 d 命令为例。d 可以和任意光标移动的操作结合,来删除一个范围的内容。

比如:w 是跳到下一个单词的开头,那么 dw 就是删除到下一个单词的开头;b 是跳转到前一个单词的开头,那么 db 就是删除到前一个单词的开头。以此类推,d0 是删除当前位置到行开头的所有内容,dG 是删除当前行到文件末尾的所有内容,dgg 是删除当前行到文件开头的所有内容。

大部分命令都支持 <verb><n><motion><n><verb><motion> 两种模式,比如 d2w2dw 都是删除后两个单词。但在语义上有区别:d2w 表示删除 2w 范围的内容,而 2dw 表示 dw 命令重复 2 次。

命令的小写和大写:d / D

不同的方向:

  • x 向右、X 向左
  • p 向下、P 向上
  • o 向下、O 向上
  • f 向右、F 向左

更严格的条件:

  • w 将特殊字符作为独立单词,W 只将空格作为单词分隔符
  • e / Eb / B 同理

更大的范围:

  • a 在当前位置后面插入、A 在当前行末尾插入
  • i 在当前位置前插入、I 在当前行开始插入
  • d 删除一个范围、D 删除到行末尾
  • c 删除一个范围、C 删除到行末尾,并进入编辑模式
  • s 删除当前字符,并进入编辑模式;S 删除当前整行,并进入编辑模式

连续操作:

  • r 替换一个字符、R 连续替换多个字符直到按下 <Esc>

两个字母重复:dd / cc / yy / guu

两个 verb 字母重复,表示对当前整行操作:

  • dd:删除整行
  • cc:删除整行,并进入编辑模式
  • yy:复制整行
  • guu:当前整行变成小写
  • gUU:当前整行变成大写

重复上次操作:. / , / ;

  • .:重复上次的编辑操作。比如执行了 A123<Esc> 在当前行尾插入 123 后,可以移动到下一行,按 . 在该行末尾插入 123
  • , / ;:重复当前行内的上一次 / 下一次 f 查找。比如在当前行按 fa 找到第一个 a 字符后,按 ; 可以查找下一个,等价于再按 fa。按 , 是查找上一个,等价于 Fa
  • n / N:按 /bar<Enter> 搜索 bar 字符串后,按 n 可以查找下一个,按 N 查找上一个。

进阶

[E] 替换一个字符:r

r:再按下任意键,替换(replace)当前字符,等同于 x + i。示例:

1
2
3
4
5
    ↓ 光标在这里
Helle, world!
# 先按 r,再按 o
Hello, world!
↑ 光标在这里

[E] 替换连续多个字符:R

R:替换连续的多个字符,按下 <Esc> 可以退出替换模式。

[E] 更改一个范围的内容:c

c 取 change 的首字母,这个命令的便捷之处在于将「删除操作」和「进入编辑模式」合二为一,可以少按一个键。

  • cw:更改下一个单词,等同于 dw + i
  • c2w:更改后两个单词,等同于 d2w + i
  • c$:更改从当前位置到行结束的所有内容,等同于 d$ + i

d 一样,c 也可以和任意光标移动的操作符结合,来更改一个范围的内容。

[E] 删除当前字符,并进入编辑模式:s

s 等同于 x + i

[E] 删除当前整行,并进入编辑模式:S / cc

S 等同于 dd + occ 也可以删除整行,并进入编辑模式。

[E] 从当前位置开始向右删除整行:D

D 等同于 d$

[E] 从当前位置开始向右删除整行,并进入编辑模式:C

C 等同于 c$,或者 d$ + a,或者 D + a

[V] 可视模式选择内容:v / V / <Ctrl> + v

按下 v 进入可视模式(visual mode),然后移动光标以选择文本。可以针对选中的文本执行任意操作 (verb),比如:

  • 按下 y 可以复制选中的文本,再移动到别的位置按下 p 粘贴这些文本
  • 按下 d 可以删除选中的文本

按下 ctrl + v 可以进入 Visual Block Mode,选择一个矩形块里的内容:

按下大写 V 可以选中整行。常见的使用技巧:

  1. V 选中整行,按 j 向下选中多行,然后 y 复制。
  2. V 选中整行,按 j 向下选中多行,按 < 向左缩进,按 . 继续缩进。
  3. V 选中整行,按 j 向下选中多行,按 = 格式化。

复制下一个单词:yw

y 取 yank(复制)的首字母。yw 复制下一个单词,p 可以将其粘贴(put)到指定位置。

事实上,ycd 一样,可以和任意光标移动的操作符结合,来复制一个范围的内容。比如 y$ 将复制当前位置到行末尾的全部内容,yh 将复制光标前面的字符,yG 复制光标所在行到最后一行的所有内容。

最后,yy 复制当前行,可以和 dd 一起理解 —— dd 删除一整行,快捷键重复表示操作的是一整行,不管光标位置在哪里。第二个 yd 并没有语义上的含义。

复制当前行:yy / 2yy / y2j

yy 复制当前行,p 粘贴到目标位置。

nyy 复制当前行往下的 n 行,包括当前行。

ynj 也是复制当前行往下的 n 行。比如 y2j 会复制当前行和下一行。

粘贴到下一行 / 上一行:p / P

如上所述,p 粘贴到目标位置。

通过 dd 删除某一行后,也可以按下 p,将删除掉的内容放置到当前光标位置下一行。注意这里是「放置」而不是「粘贴」,因为 dd 将被删除的行保存到了缓冲区,而 p 其实是将缓冲区的内容放置到当前位置,所以 p 取 put 的首字母,而非 paste。

同理,yy 将当前行保存到缓冲区,但不删除。这样 yy + p 就可以实现“复制-粘贴”的操作。

大写 P 粘贴到上一行。

当前行置顶:zt / zb / zz

zt 把当前行置于屏幕顶端。z 字取其象形意义,模拟一张纸的折叠变形。t 取 top 的首字母。

zz 将当前行置于屏幕中央。zb 将当前行置于屏幕底端,b 取 bottom 的首字母。

缩进:< / >

选中文本后,< 是向左缩进,> 是向右缩进。

格式化:=

= 可以将选中的文本格式化。这个命令可以配合 V 使用 —— 通过 V 选中多行,然后按 = 格式化选中的文本。

其他工具 Vim 化

Chrome

Vimium,通过类似 vim 风格的命令操作浏览器窗口。

VS Code

Vim 插件,将 VS Code 的编辑器转为 vim 模式。最近高频使用,Vciwdi{ 等命令显著提升了编码效率。

编辑 settings.json 文件,配置 jj 替换 ESC:

1
2
3
4
5
6
"vim.insertModeKeyBindings": [
{
"before": ["j", "j"],
"after": ["<Esc>"]
}
]

终端 / Bash / zsh

在终端输入 set -o vi 可以切换到 vim 模式,按下 ESC 就能进入 vim 的 normal mode,修改终端命令的时候很好用。推荐将其写入 .bashrc.zshrc 等配置文件。

在 zsh 中,也可以通过快捷键 Ctrl + x, Ctrl + e 打开 vim 编辑当前命令。

总结

掌握「入门」一节中的快捷键,基本可以满足大部分使用场景。如果想进一步提升效率,那么「进阶」一节中的快捷键也值得学习。

可以在其他编辑器中配合 vim 插件,来培养 vim 的使用习惯。

最后,在实践中学习命令!如果只是阅读而不尝试,那么很快就会遗忘。

希望本文对你有帮助。