文章 / 计算机
Vim
模式切换、移动、编辑与组合操作的记忆表。
本页目录 · 55 节
- 为什么要写这篇文章
- 学习资源
- 入门
- 标准模式 / 插入模式
- 执行命令::<command>
- 退出 vim::q / ZZ
- 保存文件: :w / :w <filename>
- 基本移动:h / j / k / l
- 前往第一行 / 最后一行:gg / G
- 向右移动一个单词:w / e
- 向左移动一个单词:b
- 移动到前一个单词的末尾:ge
- 前往当前行第一 / 最后字符:0 / $
- 删除字符:x / X
- 删除单词:dw
- 删除当前行:dd
- 在当前位置后面插入:a
- 在当前行开始 / 末尾插入:I / A
- 在当前行下 / 上面插入新行:o / O
- 撤销 / 重做:u / <Ctrl> + r
- 中场休息:vim 的一些模式
- 重复 n 次操作:n<key>
- 删除一个范围的内容:d<range>
- 快捷键的小写和大写
- 跨越多行选择内容:v 进入可视模式
- 进阶
- 替换一个字符:r
- 替换连续多个字符:R
- 更改一个范围的内容:c
- 复制当前行:yy
- 粘贴到下一行 / 上一行:p / P
- 移动到下一个指定字符:f<target>
- 删除当前字符,并进入编辑模式:s
- 删除当前整行,并进入编辑模式:S
- 从当前位置向右删除整行:D
- 向右删除行, 进入编辑模式:C
- 复制下一个单词:yw
- 当前行置顶:zt
- 高级
- 查找文档中的关键字:/<pattern>
- 查找当前光标对应的完整单词:*
- 在代码块匹配的括号之间跳转:%
- 跳转前 / 后一个位置:<Ctrl> + o / i
- 替换:{range}s/{old}/{new}/{flag}
- 在 vim 中执行 shell 命令::!<command>
- 配置文件
- 配置插件
- 其他工具 Vim 化
- 总结
- 附录 1:速查表
- 光标移动
- 屏幕滚动
- 编辑
- 其他
- 附录 2:vim 命令
为什么要写这篇文章
最近遇到在服务端编辑代码文件、查日志的场景比较多,所以想要系统学习一下 vim。
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 编辑器:非常推荐的课程,所有内容都很有帮助
-
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
入门
标准模式 / 插入模式
- 标准模式(Normal Mode):进入 vim 的默认模式,这个模式下按下任何键不会实际输入到文本中,按下
:可以执行命令 - 插入模式(Insert Mode):在标准模式按下
i进入插入模式,此时可以输入文本;按下<ESC>退出插入模式
可以配置 ii 退出插入模式,这样左手不需要移动到最左上角去按下 <ESC>。在标准模式下执行:
imap ii <Esc>
可以将这条命令写到 vim 的配置文件中。这条配置只会影响需要输入_连续的_两个 i 的场景:如果想要输入连续的两个 i,必须在按下第一个 i 之后稍等一会儿,再按第二个 i。不过英文中很少有单词包含连续的两个 i,所以影响可以忽略。
执行命令::<command>
按下 : 后输入命令,按回车执行。如 :set number 会显示行号。
退出 vim::q / ZZ
:q/:quit:退出 vim,不作任何改动:q!:退出 vim,丢弃已有的改动:wq:保存更改(write)并退出(quit)vimZZ:等同于:wq,这个快捷键输入比:wq更快,注意是大写Z
保存文件: :w / :w <filename>
:w:保存更改:w <filename>:保存到一个新的文件
基本移动:h / j / k / l
使用 h、j、k、l 而不是 ←、↓、→、↑,这能够避免将手指移出键盘热区再移回来。如果有必要的话,甚至可以禁用方向键,来强制自己使用 h、j、k、l:
map <Left> <Nop>
map <Right> <Nop>
map <Up> <Nop>
map <Down> <Nop>
前往第一行 / 最后一行:gg / G
gg:前往第一行1G:同ggG:前往最后一行
向右移动一个单词:w / e
w:向右移动一个单词,光标将落在下一个单词的首字符e:向右移动一个单词,光标将落在当前一个单词的最后一个字符
在这里,连续的「数字+字母」、「特殊字符」视为一个单词。示例:
↓ 光标在这里
Hello, world!
↑ 按下 w
↑ 按下 e
Hello, world!
↑ 按两下 w
↑ 按两下 e
类似的还有 W / E,区别在于这两个快捷键将「空格」作为单词的分隔符。示例:
↓ 光标在这里
Hello, world!
↑ 按下 W
↑ 按下 E
Hello, world!
↑ 按两下 E
↑ 按两下 W 会移动到下一行
向左移动一个单词:b
b 向左移动到前一个单词的首字符,相当于是 w 的逆操作。b 取 backwards 首字母,「单词」的定义同 w。
2b 向左移动两个单词,nb 向左移动 n 个单词。
B 向左移动一个单词,将「空格」作为单词的分隔符(同 W、E)。
单词移动类快捷键速记:web。
移动到前一个单词的末尾:ge
ge 移动到前一个单词的末尾,gE 将空格作为单词的分隔符。
前往当前行第一 / 最后字符:0 / $
0:前往第一个字符,可以理解成是第 0 列$:前往最后一个字符
删除字符:x / X
x:删除当前字符,等同于<Delete>X:删除前一个字符
删除单词:dw
「单词」的定义同 w,单词后面的任意多个空格将被删除。
类似的还有 dW,删除下一个空格前的单词。
删除当前行:dd
略。
在当前位置后面插入:a
i 在当前位置前面插入(insert),a 在当前位置后面插入(append)。
在当前行开始 / 末尾插入:I / A
略。
在当前行下 / 上面插入新行:o / O
插入新的空白行。
撤销 / 重做:u / <Ctrl> + r
u:撤销(undo)<Ctrl> + r:重做(redo)
中场休息:vim 的一些模式
重复 n 次操作:n<key>
Vim 中几乎所有操作都可以通过一个 n 前缀来重复 n 次:
- 多次方向移动:
nh/nj/nk/nl。5h向左移动 5 个字符,5j向下移动 5 行。 - 向左移动多个单词:
nb。2b向左移动两个单词。 - 前往第 n 行:
nG。1G可以前往第一行,就是这个原理。如果希望在 vim 中显示行号,可以在标准模式下执行set number命令,也可以将这条命令写到 vim 的配置文件中。 - 删除多个字符:
nx。2x删除两个字符,2X向左删除两个字符。 - 移动多个单词:
nw/ne。2w/2e向右移动两个单词,等同于按两次w/e,示例:
↓ 光标在这里
Hello, world!
↑ 按下 2w
↑ 按下 2e
- 删除多个单词:
dnw/ndw。d2w/2dw删除光标后的两个单词。类似的还有dnW,删除后面第 n 个空格之前的单词。 - 删除多个行:
dnd/ndd。d2d/2dd都可以删除光标开始的两行。 - 多次撤销:
nu。2u撤销前两步操作,等同于按两次u。 - 多次重做 /
n<Ctrl> + r。2<Ctrl> + r重做被撤销的两步操作,等同于按两次<Ctrl> + r。
删除一个范围的内容:d<range>
d 可以和任意光标移动的操作符结合,来删除一个范围的内容。
这里,我们先明确一下「范围」的定义:
- 对于单词级别的移动,这个范围将是光标前后所处的位置对应的左闭右开的区间(
$是个例外) - 对于行级别的移动,这个范围将是光标前后所处的位置之间的所有行,包含光标所在的两个行
而且,d 可以向任意方向进行删除,都符合上述约定。
可以打开 vimtutor 尝试一下这些命令,就可以理解上述“范围”的含义:
dw:删除下一个单词,不会删除w跳转到的那个字符db:删除前一个单词,不会删除光标一开始指向的那个字符d0:删除当前位置到行开头的所有内容,不会删除光标一开始指向的那个字符dG:删除当前行到文件末尾的所有内容,包含当前行在内也会被删除dgg:删除当前行到文件开头的所有内容,包含当前行在内也会被删除,d1G可以达到相同的效果
$ 是一个例外,d$ 会删除当前位置到行末尾的所有内容,包含行末尾在内的字符也都会被删除。
这些命令不用可以去记,只需要记住上面「范围」的规则即可。比如 3G 会跳到第 3 行,那么 d3G 将删除当前行到第 3 行的所有内容,包括第 3 行;j 下移一行,那么 dj 将删除当前行和下一行,d2j 将删除当前行开始的 3 行内容;dh、dl 分别等价于 x、X…… 理解之后,你就可以做到举一反三了。
最后再补充一下:d 和数字 n 可以组合在一起使用。d 表示删除元素,n 表示后面的命令重复 n 次。这两个命令以不同顺序组合也能达到相同的效果,比如 d2w 和 2dw 都是删除后两个单词。但我个人认为,这两个命令在语义上有区别:d2w 表示删除 2w 范围的内容,而 2dw 表示 dw 命令重复 2 次。
在 vim 术语中,将
d后面的操作称为[number]与motion,其中number是可选的。 比如d2w中,2就是number,w是motion。 本文为了便于理解,统称其为range。
快捷键的小写和大写
部分快捷键见「进阶」一节
不同的方向:
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>
跨越多行选择内容:v 进入可视模式
按下 v 进入可视模式(visual mode),然后移动光标以选择文本:
- 按下
y可以复制选中的文本 - 按下
d可以删除选中的文本,按下p放置(粘贴)这些文本,这就实现了剪切功能

进阶
替换一个字符:r
r:再按下任意键,替换(replace)当前字符,等同于 x + i。示例:
↓ 光标在这里
Helle, world!
# 先按 r,再按 o
Hello, world!
↑ 光标在这里
替换连续多个字符:R
R:替换连续的多个字符,按下 <Esc> 可以退出替换模式。
更改一个范围的内容:c
c 取 change 的首字母,这个命令的便捷之处在于将「删除操作」和「进入编辑模式」合二为一,可以少按一个键。
cw:更改下一个单词,等同于dw+ic2w:更改后两个单词,等同于d2w+ic$:更改从当前位置到行结束的所有内容,等同于d$+i
和 d 一样,c 也可以和任意光标移动的操作符结合,来更改一个范围的内容。
复制当前行:yy
yy 复制当前行,p 粘贴到目标位置。
nyy 复制当前行向下的多行。
粘贴到下一行 / 上一行:p / P
如上所述,p 粘贴到目标位置。
通过 dd 删除某一行后,也可以按下 p,将删除掉的内容放置到当前光标位置下一行。注意这里是「放置」而不是「粘贴」,因为 dd 将被删除的行保存到了缓冲区,而 p 其实是将缓冲区的内容放置到当前位置,所以 p 取 put 的首字母,而非 paste。
同理,yy 将当前行保存到缓冲区,但不删除。这样 yy + p 就可以实现“复制-粘贴”的操作。
大写 P 粘贴到上一行。
移动到下一个指定字符:f<target>
ft 移动到下一个 t 出现的位置,f2 移动到下一个 2 出现的位置。f 取 forward 的首字母。
F 类似于 f,向前移动到前一个指定字符。
t 类似于 f,只不过光标会移动到下一个指定字符之前;T 类似于 F,只不过光标会移动到前一个指定字符之后。t 取 until 的含义。
示例:
↓ 光标在这里
Hello, world!
↑ fo
↑ fr
↑ Fh
↑ to
↑ Th
删除当前字符,并进入编辑模式:s
s 等同于 x + i。
删除当前整行,并进入编辑模式:S
S 等同于 dd + o。
从当前位置向右删除整行:D
D 等同于 d$。
向右删除行, 进入编辑模式:C
C 等同于 c$,或者 d$ + a,或者 D + a。
复制下一个单词:yw
y 取 yank(复制)的首字母。yw 复制下一个单词,p 可以将其粘贴(put)到指定位置。
事实上,y 和 c、d 一样,可以和任意光标移动的操作符结合,来复制一个范围的内容。比如 y$ 将复制当前位置到行末尾的全部内容,yh 将复制光标前面的字符,yG 复制光标所在行到最后一行的所有内容。
最后,yy 复制当前行,可以和 dd 一起理解 —— dd 删除一整行,快捷键重复表示操作的是一整行,不管光标位置在哪里。第二个 y 和 d 并没有语义上的含义。
当前行置顶:zt
zt 把当前行置于屏幕顶端。z 字取其象形意义,模拟一张纸的折叠变形。t 取 top 的首字母。
zz 将当前行置于屏幕中央。zb 将当前行置于屏幕底端,b 取 bottom 的首字母。
高级
查找文档中的关键字:/<pattern>
/ 从光标所在位置向后查找关键字,n / N 查找下一个 / 上一个匹配的位置。
? 向前查找,不过很少使用。如果想向前查找的话,使用 / + N 就可以了。
q/、q? 可以列出 /、? 的查找历史,上下选择,按 i 编辑,回车执行,:q退出。
<pattern> 可以是正则表达式,比如 /vim$ 查找位于行尾的 vim。查找特殊字符时需要转义,比如 /vim\$ 查找 vim$。
在查找模式中加入 \c 表示大小写不敏感查找,\C 表示大小写敏感,比如 /foo\c 会查找 foo、Foo 等。默认是大小写敏感,可以执行 :set ignorecase 或写入配置文件设置大小写不敏感为默认的查找模式。
查找相关命令:
set ic // 等价于 set ignorecase
set hls is // 高亮匹配项
nohlsearch // 移除匹配项的高亮显示
查找当前光标对应的完整单词:*
示例:
↓ 光标在这里
Hello, world!
此时按下*,将查找 Hello 这个单词,并且要求 Hello 出现位置的前后均为空白字符或标点符号,即查找完整独立的单词。
在代码块匹配的括号之间跳转:%
% 在匹配的括号之间跳转。需要将光标放在 {}[]() 上,然后按 %。 如果光标所在的位置不是 {}[](),那么会向右查找第一个 {}[]()。
跳转前 / 后一个位置:<Ctrl> + o / i
在标准模式下,<Ctrl> + o 将光标跳转到前一个位置,<Ctrl> + i 跳转到后一个位置。
注意这里使用的是“跳转”。h / j/ k / l / w 等移动将不会记录在「跳转表」中,只有通过 gg / nG / 查找时的 n / N 等命令执行的跳转操作,才可以通过 <Ctrl> + o / <Ctrl> + i 来回跳转。
补充:
- 在 VS Code 中,向前一个 / 后一个位置跳转的快捷键是
<Ctrl> + [/<Ctrl> + ]。- 在 Intellij 等 Jetbrains 系列软件中,向前一个 / 后一个位置跳转的快捷键是
<Command> + [/<Command> + ]。如果不是,可以在Preferences中搜索back,然后在KeyMap -> Main menu -> Navigate -> Back中设置。
替换:{range}s/{old}/{new}/{flag}
:s(substitute)命令用来查找和替换文本。语法如下:
:{range}s/{old}/{new}/{flag}
表示在指定范围 range 内查找字符串 old 并替换为 bar,flag 说明了替换模式,如只替换首次出现、或全部替换。
作用范围 range
作用范围分为当前行、全文、行范围、选区等:
- 当前行:空白,默认,如
:s/foo/bar/g - 全文:
%,如:%s/foo/bar/g - n
m 行:12 行n,m,如:5,12s/foo/bar/g表示 5 - 当前行与之后 n 行:
.,+n,如:.,+2s/foo/bar/g表示当前行与之后 2 行 - 选区:略
替换模式 flag
替换模式:
- 空白:默认,只替换光标位置之后的首次出现,如
:%s/foo/bar g:全局替换,替换每次出现(global),如:%s/foo/bar/gi:忽略大小写c:交互式替换,每次替换前需要用户确认(confirm),如:%s/foo/bar/gc表示查找全文的所有foo并替换为bar,每次替换前都需要确认:- 按下回车执行后,提示
replace with bar (y/n/a/q/l/^E/^Y)? y表示替换n表示不替换a表示替换后续所有q表示退出查找模式l表示替换当前位置并退出查找模式^E、^Y用于向上、向下滚动屏幕,^表示<Ctrl>键
- 按下回车执行后,提示
在 vim 中执行 shell 命令::!<command>
比如通过 vim 编辑文本的时候,希望打印当前目录,但是又不想退出 vim,那么就可以直接在 vim 中执行::!pwd,这等同于在 shell 中执行 pwd。
获得命令提示::<prefix> + <Ctrl> + d
在 vim 中输入 :,再按下 <Ctrl> + d,将展示所有可以在 vim 中使用的命令。
输入 :w,再按下 <Ctrl> + d,将展示所有可以在 vim 中使用的、以 w 开头的命令。
配置文件
配置文件位于 ~/.vimrc,其内容是若干行可在 vim 中执行的命令,会在每次打开 vim 时自动执行。示例:
set number # 显示行号
set ignorecase # 大小写不敏感查找
set ic // 等价于 set ignorecase
set smartcase # 如果有一个大写字母,则切换到大小写敏感查找
set hls is // 高亮匹配项
nohlsearch // 移除匹配项的高亮显示
Github 有很多开箱即用的 vimrc 文件,比如 amix/vimrc。
配置插件
其他工具 Vim 化
- Chrome:Vimium,通过类似 vim 风格的快捷键操作浏览器窗口
- VS Code:Vim 插件,将 VS Code 的编辑器转为 vim 模式
总结
掌握「入门」一节中的快捷键,基本可以满足大部分使用场景。如果想进一步提升效率,那么「进阶」一节中的快捷键也值得学习。「高级」一节的内容,由于我还没有将 vim 作为主力开发工具,尚未深入研究,所以等以后有机会再补充。
可以在其他编辑器中配合 vim 插件,来培养 vim 的使用习惯。将 Chrome vim 化,也能体验到 vim 带来的酷炫与极客感。
最后,在实践中学习命令!如果只是阅读而不尝试,那么很快就会遗忘。
希望本文对你有帮助。
附录 1:速查表
仅作为正文的补充,记录一些可能有用的快捷键。
光标移动
| 快捷键 | 作用 |
|---|---|
^ | 移动到当前行第一个非空字符 |
<Space> | 向右移动一个字符,等同于 l |
<Alt> + ←, <Alt> + → | 向左 / 向右移动一个单词,等同于 w / b |
:n<enter> | 跳到指定行,等同于 nG |
ngg | 跳到指定行,等同于 nG |
H | 光标移动到屏幕最上方(head) |
M | 光标移动到屏幕中央(middle) |
L | 光标移动到屏幕最下方(last) |
屏幕滚动
| 快捷键 | 作用 |
|---|---|
| 向上 / 向下滚动一行 | <Ctrl> + y / <Ctrl> + e |
| 向上 / 向下滚动一页 | <Ctrl> + f / <Ctrl> + b(forward,backward) |
| 向上 / 向下滚动半页 | <Ctrl> + d / <Ctrl> + u |
这些命令在大部分 Unix 软件中都可以使用,比如
man、less、tmux(需要先进入滚动模式)
编辑
| 快捷键 | 作用 |
|---|---|
ddp | 上下两行交换,实际上就是 dd + p |
J | 将当前行和下一行用空格连成一行 |
Jx | 将当前行和下一行直接连成一行,相当于在下一行的行首按 <Backspace> |
其他
| 快捷键 | 作用 |
|---|---|
:help | 查看帮助文档 |
:help :{command} | 查看一个具体命令的帮助文档,如 :help :q 查看 :q 的帮助文档 |
^y$ | 复制一行 |
ggyG | 复制整个文件 |
q: | 查看历史命令,上下选择,按 i 编辑,回车执行,:q退出 |
附录 2:vim 命令
可以在 vim 标准模式下输入 :<command> 执行,也可以写入配置文件。
set number # 显示行号
set ignorecase # 大小写不敏感查找
set smartcase # 如果有一个大写字母,则切换到大小写敏感查找
imap ii <Esc> # 在插入模式下,映射 ii 到 <Esc>
# 在标准模式下,禁用方向键
map <Left> <Nop>
map <Right> <Nop>
map <Up> <Nop>
map <Down> <Nop>
set paste # 进入粘贴模式,这可以避免粘贴多行代码时被自动缩进
set nopaste # 粘贴完之后,执行这条命令退出粘贴模式
📒 相关文章:💻【Linux】GDB 学习笔记