Vim 对于每个开发人员都不陌生,这可能是我们接触最多的 Linux 软件。所有类 Unix 的系统(Linux、Mac)都安装了 vim。当我们通过终端操作文本时,vim 或许是我们唯一的选择。
然而,vim 的使用方式和我们所熟悉的可视化编辑器完全不同,它的的快捷键是如此奇怪,不易上手。因此除非兴趣使然,我们很少会主动学习 vim。它的上限够高,下限也足够低,只需要掌握最基本的操作:↑↓←→
、i
、<ESC>
、:wq
,就可以覆盖大部分使用场景。那为什么还需要再深入学习 vim 呢?
主要原因是:用较少的学习成本,换来较大的效率提升。Vim 常用的几个快捷键,可以在手指不离开键盘热区的情况下快速定位光标或编辑内容,这些内容的学习成本并不高。如果你开发运维的过程中和 vim 打交道的次数越来越多,掌握这些技巧可以极大的提升开发效率。即使现在没有需求,也可以提前上手这个强大的工具。
为什么写这篇文章
现有的 vim 教程 / 文章大多直接罗列完整的 vim 快捷键列表,让人不知从何下手。我认为应当先掌握最重要的、最高频的快捷键,满足日常开发所需;其他低频使用的快捷键,可以作为一个速查表按需查看,vim 的进阶用法也可以之后再深入研究。
因此,我尝试作为一个 vim 初学者,总结 vim 主要和次要的快捷键,同时提供一些学习 vim 的资源。
注意:在阅读本文时,你随时可以在终端执行 vimtutor
,打开一个教程文本文件,尝试某个快捷键或命令。
学习资源
- Missing Semester - 3. Vim 编辑器:非常推荐的课程,所有内容都很有帮助
- Mastering Vim:讲解 vim 里的“编程语言范式”,整体理解 vim
- The Vim Tutorial Part One - Youtube, Part Two:看英文字幕比较吃力的话,可以直接看本文
- vimtutor:安装 vim 后自带的教程,在终端执行
vimtutor
即可打开,mac 系统下是中文文档 - Vim Adventure:以游戏的方式学习 vim
这里顺便再推荐一些可视化学习资源:
- 数据结构与算法:Data Structure Visualization、Visualgo
- 正则表达式:regexper
- Git:Learn Git Branching(强烈推荐)、Visualizing Git
术语说明
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)vimZZ
:等同于:wq
,这个快捷键输入比:wq
更快,注意是大写Z
保存文件: :w
/ :w <filename>
:w
:保存更改:w <filename>
:保存到一个新的文件
[M] 基本移动:h
/ j
/ k
/ l
使用 h
、j
、k
、l
而不是 ←
、↓
、→
、↑
,这能够避免将手指移出键盘热区再移回来。如果有必要的话,甚至可以禁用方向键,来强制自己使用 h
、j
、k
、l
:
1 | map <Left> <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 | ↓ 光标在这里 |
类似的还有 W
/ E
,区别在于这两个快捷键对单词
的定义是连续的「非空字符」,即以空格作为单词的分界线。比如 hello, world!!!
里,包含 hello,
和 world!!!
两个单词。
[M] 向左移动一个单词:b
b
向左移动到前一个单词的首字符,相当于是 w
的逆操作。b
取 backwards 首字母,「单词」的定义同 w
。
2b
向左移动两个单词,nb
向左移动 n 个单词。
B
向左移动一个单词,将「空格」作为单词的分隔符(同 W
、E
)。
[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 | ↓ 光标在这里 |
[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
撤销前两步操作,等同于按两次u
。2<Ctrl> + r
重做被撤销的两步操作,等同于按两次<Ctrl> + r
。
操作任意范围:<verb><motion>
我们以 d
命令为例。d
可以和任意光标移动的操作结合,来删除一个范围的内容。
比如:w
是跳到下一个单词的开头,那么 dw
就是删除到下一个单词的开头;b
是跳转到前一个单词的开头,那么 db
就是删除到前一个单词的开头。以此类推,d0
是删除当前位置到行开头的所有内容,dG
是删除当前行到文件末尾的所有内容,dgg
是删除当前行到文件开头的所有内容。
大部分命令都支持 <verb><n><motion>
和 <n><verb><motion>
两种模式,比如 d2w
和 2dw
都是删除后两个单词。但在语义上有区别:d2w
表示删除 2w
范围的内容,而 2dw
表示 dw
命令重复 2 次。
命令的小写和大写:d
/ D
等
不同的方向:
x
向右、X
向左p
向下、P
向上o
向下、O
向上f
向右、F
向左
更严格的条件:
w
将特殊字符作为独立单词,W
只将空格作为单词分隔符e
/E
、b
/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 | ↓ 光标在这里 |
[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
+ o
。cc
也可以删除整行,并进入编辑模式。
[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
可以选中整行。常见的使用技巧:
- 按
V
选中整行,按j
向下选中多行,然后y
复制。 - 按
V
选中整行,按j
向下选中多行,按<
向左缩进,按.
继续缩进。 - 按
V
选中整行,按j
向下选中多行,按=
格式化。
复制下一个单词:yw
y
取 yank(复制)的首字母。yw
复制下一个单词,p
可以将其粘贴(put)到指定位置。
事实上,y
和 c
、d
一样,可以和任意光标移动的操作符结合,来复制一个范围的内容。比如 y$
将复制当前位置到行末尾的全部内容,yh
将复制光标前面的字符,yG
复制光标所在行到最后一行的所有内容。
最后,yy
复制当前行,可以和 dd
一起理解 —— dd
删除一整行,快捷键重复表示操作的是一整行,不管光标位置在哪里。第二个 y
和 d
并没有语义上的含义。
复制当前行: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 模式。最近高频使用,V
、ciw
、di{
等命令显著提升了编码效率。
编辑 settings.json
文件,配置 jj
替换 ESC:
1 | "vim.insertModeKeyBindings": [ |
终端 / Bash / zsh
在终端输入 set -o vi
可以切换到 vim 模式,按下 ESC
就能进入 vim 的 normal mode,修改终端命令的时候很好用。推荐将其写入 .bashrc
或 .zshrc
等配置文件。
在 zsh 中,也可以通过快捷键 Ctrl + x, Ctrl + e
打开 vim 编辑当前命令。
总结
掌握「入门」一节中的快捷键,基本可以满足大部分使用场景。如果想进一步提升效率,那么「进阶」一节中的快捷键也值得学习。
可以在其他编辑器中配合 vim 插件,来培养 vim 的使用习惯。
最后,在实践中学习命令!如果只是阅读而不尝试,那么很快就会遗忘。
希望本文对你有帮助。