《Vim 实用技巧》(第 2 版)
阅读信息
- 评分:⭐️⭐️⭐️⭐️⭐️
- 时间:6/4/2026 → 6/15/2026
- 读后感:学习 Vim 的必读书目。一次投入,终生受益!学习 Vim 最好的时代已经到来,让 AI 帮你搞定复杂的配置与繁多的操作命令,你只需要专注于编程,剩下的交给 Vim!

为什么要学习 Vim / Neovim?
每位开发者都值得投入时间深入学习 Vim 的核心操作。在当今的开发生态下,结合现代化的 Neovim 与开箱即用的发行版(如 LazyVim),能够让你的编码效率实现质的飞跃。
过去,Neovim 的配置门槛较高,繁琐的插件安装与易错的调试过程常常让新手望而却步,热情在挫败感中消磨殆尽。然而,随着 AI 技术的普及,现在我们完全可以将复杂的配置与排错工作交给 AI 助手。这极大地降低了上手难度,让快速构建专属开发环境变得轻松自如。
面对 Vim 庞杂的命令体系,初学者也大可不必焦虑。在学习初期,借助 AI 实时解答命令用法,不仅能快速跨越陡峭的学习曲线,还能在实践中迅速建立肌肉记忆。
将 Neovim 作为主力编辑器的优势显而易见:
- 打造稳定且跨越时代的开发利器:它是永久免费的终端神器,无需因为潮流更迭而频繁迁移或重新适应各种臃肿的商业 IDE。
- 实现真正的“双手不离键盘”:熟练后,编码、调试、单元测试乃至 HTTP 请求测试等日常操作均可通过键盘高效完成,让思维与代码实现无缝衔接。
- 洞悉现代编辑器底层机制:折腾配置的过程,也是深入理解 LSP(Language Server Protocol)、DAP(Debugging Adapter Protocol)、Treesitter 语法树等 IDE 核心技术的绝佳机会。
Vim 的核心“语法”
Vim 的核心操作逻辑可以总结为一套优雅的“语法”:[次数] + [动词/操作] + [名词/范围](即 [count] + [operation] + motion/text object)。掌握了这个公式,你就能像说话一样组合出无穷无尽的操作指令。
学习路线
Vim 的学习是一个循序渐进的过程,可以分为以下三个阶段。不必追求一步到位,每完成一个阶段都会带来明显的效率提升。
第一阶段:基础生存(入门)
目标是能够用 Vim 独立完成日常编辑任务,不再依赖鼠标。
- 五种模式:牢固区分普通模式 (Normal)、插入模式 (Insert)、可视模式 (Visual)、命令行模式 (Command-line) 和替换模式 (Replace) 的用途与切换方式(
i、<Esc>、v、:)。
- 基本移动:掌握
h/j/k/l 字符级移动,w/b/e 单词级移动,0/$ 行首行尾,gg/G 文件首尾,以及 {/} 段落间跳转。
- 核心编辑语法:理解并练习
[count] + [verb] + [noun] 的组合公式(如 d2w、ci"),这是 Vim 一切高效操作的根基。
- 基础增删改查:熟练使用
x、dd、yy、p、u(撤销)、<C-r>(重做)以及 / 查找与 n/N 翻查。
- 保存与退出:
:w、:q、:wq、:q! 等命令行操作。
第二阶段:进阶提升(核心)
这也是《Vim 实用技巧》一书中反复强调的精髓,是区分 Vim 新手与高手的分水岭。
- 点命令 (The Dot Command):微观层面的自动化。
. 能够重复上一次的修改操作。构建"可重复"的编辑序列,是核心思维定式(即"一击移动,一击执行")。
- 寄存器 (Registers):Vim 强大的剪贴板系统。除了默认的无名寄存器,还需掌握命名寄存器(
"a-"z,用于长期存储)、系统剪贴板("+,与外部交互)、黑洞寄存器("_,用于彻底删除不污染剪贴板)以及表达式寄存器("=,可当作计算器使用)。
- 宏 (Macros):宏观层面的自动化。通过
q 录制一系列复杂的击键动作,并可在多处(甚至跨文件)完美重放(@),是应对大规模代码格式化和重复性劳动的终极武器。
- 模式匹配与替换 (Search and Substitute):熟练掌握
/ 查找与 :s 替换。结合 Vim 强大的正则表达式(以及 \v Very Magic 模式),能够在重构代码时提供极高的精确度和效率。
- 跳转列表与标记 (Jumps and Marks):利用
m 设定局部或全局标记(Marks),或使用 <C-o> 和 <C-i> 在跳转列表 (Jumplist) 中穿梭,实现代码阅读时的快速"折返跑"。
- 多文件与工作区管理:彻底理清缓冲区 (Buffers)(内存中打开的文件)、窗口 (Windows)(可见的视图分割)和标签页 (Tabs)(窗口的集合)这三者的关系,能让你在处理大型项目时游刃有余。
第三阶段:精通内化(长期)
此阶段没有终点,核心是将 Vim 的思维方式完全内化,使其成为本能。
- 打磨个人配置:基于 LazyVim 等发行版,按需定制快捷键、插件与工作流,打造真正属于自己的"神器"。
- 命令行工具联动:将 Vim 与
grep、sed、awk、git 等命令行工具深度整合,发挥文本处理的极限威力。
- LSP 与现代开发工作流:熟练配置与使用代码补全、诊断、重构(重命名、引用查找)等 IDE 级功能。
- 持续输出与迭代:通过阅读他人的
dotfiles、参与社区、记录自己的常用技巧,在实践中不断打磨与精进。
Normal 模式
光标移动
行跳转
| 指令 |
说明 |
h / j / k / l |
实际行左 / 下 / 上 / 右 |
gj / gk / g0 / g^ / g$ |
按屏幕行移动 |
gg / G |
跳到第一行 / 最后一行 |
{line}gg / {line}G |
跳到指定行 |
( / ) |
跳转到上 / 下一句的开头 |
{ / } |
跳转到上 / 下一段落/函数/代码块的开头 |
gf |
跳转到光标下的文件名(go to file) |
gd / gD |
跳转到局部/全局定义 |
<Ctrl-]> |
跳转到光标下关键字的定义处 |
词跳转
| 指令 |
说明 |
w / b |
跳到下 / 上一单词开头 |
e / ge |
跳到下 / 上一单词结尾 |
W / B / E / gE |
在连续非空字符(字串)间跳转 |
0 / ^ / $ |
跳到行首 / 行首非空字符 / 行尾 |
% |
跳到匹配的配对符号 |
* / # |
向后 / 向前精确搜索光标所在词 |
g* / g# |
向后 / 向前部分匹配包含光标所在词的文本 |
f{char} / F{char} |
向后 / 向前跳到当前行某字符上,; / , 正向或反向继续跳 |
t{char} / T{char} |
向后 / 向前跳到指定字符的前一个位置(till) |
翻页
| 指令 |
说明 |
zz / zt / zb |
光标行设为屏幕居中 / 顶部 / 底部 |
Ctrl+u / Ctrl+d |
向上 / 向下半屏滚动 |
Ctrl+b / Ctrl+f |
向上 / 向下整屏滚动 |
标记
| 指令 |
说明 |
m{mark} |
标记当前位置,a-z 局部(缓冲区内),A-Z 全局(跨文件跨会话) |
`{mark} |
跳转到指定标记 |
`` / `. / `^ / `0 |
跳转到上次跳转前 / 修改 / 插入的位置 / 退出 Vim 时的位置 |
`[ / `] |
上次修改或复制的起始 / 结束位置 |
`< / `> |
上次高亮选区的起始 / 结束位置 |
y`a |
复制当前位置到标记 a 的内容 |
页面内搜索
| 指令 |
说明 |
/{pattern} |
向后查找,支持正则 |
?{pattern} |
向前查找 |
n / N |
向后 / 向前跳转匹配项 |
操作符与动作
语法:[count] + Operator + Motion/TextObject,操作符连按两次作用于当前行(如 dd、yy)。操作符详见文本变换,Motion 详见词跳转与页面内搜索,TextObject 详见文本对象。
| 指令 |
说明 |
. |
重复上一个操作 |
u / Ctrl+r |
撤销 / 重做 |
r{char} |
替换光标下一个字符后返回 Normal 模式 |
R |
进入 Replace 模式,持续替换字符直到 <Esc> |
<Ctrl-o> / <Ctrl-i> |
跳到跳转列表中较旧 / 较新的位置(<Ctrl-i> 与 <Tab> 等价) |
:set relativenumber / :set norelativenumber |
开启 / 关闭相对行号 |
文本对象
| 指令 |
说明 |
[count]{operator}{i\|a}{object} |
i=内容,a=包含边界;对象:w/W(词)、s(句)、p(段)、{}、[]、()、<>、'、"、t(HTML/XML 标签) |
| 括号类文本对象别名 |
b=)、B=}、r=]、a=>,如 dab=da)、diB=di} |
文本操作
| 指令 |
说明 |
gu / gU / g~ |
转小写 / 转大写 / 翻转大小写 |
guu / gUU |
当前行转小写 / 转大写 |
J / gJ |
将下一行合并到当前行,并在两部分文本之间插入一个/不插入空格 |
gwip |
根据 textwidth 自动折行 |
Ctrl+a / Ctrl+x |
增加 / 减少数字 |
g<Ctrl+a> |
创建递增序列 |
< / > |
左 / 右缩进(详见缩进) |
p / P |
在光标后 / 前粘贴,光标停在粘贴内容的起始位置 |
gp / gP |
同 p / P,但光标停在粘贴内容的末尾位置 |
]p |
粘贴并自动调整缩进至当前行层级 |
缩进
| 指令 |
说明 |
>> / << |
将当前行向右 / 左缩进,宽度由 shiftwidth 控制 |
>% / <% |
向右 / 左缩进 () 或 {} 内的区域(光标需置于括号上) |
>ib |
向右缩进 () 内的区域 |
>at |
向右缩进 <> 标签内的区域 |
== |
自动缩进当前行 |
{n}== |
自动缩进 n 行(如 3==) |
=% |
自动缩进 () 或 {} 内的区域(光标需置于括号上) |
=iB |
自动缩进 {} 内的区域 |
gg=G |
自动缩进整个缓冲区 |
折叠
| 指令 |
说明 |
zf |
定义折叠(需配合 motion / 选区使用) |
zd |
删除光标位置的折叠 |
za |
切换光标位置折叠的展开 / 关闭状态(一次) |
zo / zc |
展开/关闭光标位置的折叠(一次) |
zO / zC |
递归展开/关闭光标处的所有折叠 |
zr / zm |
降低/提高一级折叠层级(展开/关闭一级) |
zR / zM |
递归展开/关闭所有折叠 |
zi |
开启 / 关闭折叠功能(foldenable 开关) |
[z / ]z |
跳到当前折叠的开始 / 结束位置 |
Insert 模式
| 指令 |
说明 |
i / a |
在光标前 / 后插入 |
I / A |
在行首 / 行尾插入 |
o / O |
在当前行下方 / 上方插入新行 |
s / S |
删除光标字符 / 当前行后进入插入模式。S 等同于 cc |
插入模式内 Ctrl 快捷键
| 指令 |
说明 |
<Ctrl-w> |
删除光标前的单词 |
<Ctrl-t> / <Ctrl-d> |
向右/向左缩进(宽度由 shiftwidth 控制),无论光标在哪儿都能缩进 |
<Ctrl-n> / <Ctrl-p> |
自动补全:下一个/上一个匹配项 |
<Ctrl-r>{x} |
插入寄存器 x 的内容 |
<Ctrl-o>{cmd} |
临时切换到 Normal 模式执行一条命令后返回(可用于插入模式的快速执行) |
Visual 模式
| 指令 |
说明 |
v |
字符选择模式 |
V |
行选择模式 |
<Ctrl-v> |
列(块)可视模式 |
gv |
重选上次的高亮选区 |
o / O |
光标在选区首尾之间移动 |
. |
重复可视模式的操作(如 >. 多次缩进) |
Command 模式
基础命令
| 指令 |
说明 |
:w |
保存文件 |
:q |
退出 |
:q! |
不保存强制退出 |
:wq / ZZ |
保存并退出 |
:w !sudo tee % |
修改 root 文件时强制保存文件 |
:e! |
重新加载文件(丢弃未保存的修改) |
:n |
跳到第 n 行(同 ngg / nG) |
:set list / :set nolist / :set list! |
显示 / 隐藏 / 切换隐藏字符 |
:h {command} |
查看命令文档 |
历史命令
| 指令 |
说明 |
@: |
执行上一次命令行命令 |
@@ |
第一次 @: 后,继续用 @@ 重复 |
: 后按 <Up> |
查找最近命令,可输入前缀过滤 |
q: |
打开历史命令窗口,j/k 选择,Enter 执行,:q 退出 |
:!! |
重复执行上一次外部 shell 命令 |
:changes |
列出本次会话的所有变更 |
:ju[mps] |
列出跳转历史记录 |
q/ / q? / q: |
打开正向查找 / 反向查找 / 命令的历史窗口 |
/<Up> / ?<Up> / :<Up> |
打开最近的正向 / 反向查找 / 命令历史 |
范围操作
range 地址语法:行号、$(末行)、.(当前行)、%(全文)、'</'>(选区首尾)、/{pattern}/(匹配行),支持偏移如 .+3、$-3。
| 指令 |
说明 |
:[range] delete/yank [x] |
删除 / 复制(到寄存器 x) |
:[range] copy/move {addr}(简写 :t / :m) |
复制 / 移动到 addr 行后;:6t. 把第 6 行复到当前行下;:t. 复制当前行;:t$ 复到文末 |
:[range] normal {commands} |
对 range 内每行执行 Normal 模式命令 |
:[range1] g/{pattern}/[range2][cmd] |
对含 pattern 的行执行 Ex 命令;range1 限定检索范围(默认全文),range2 限定执行范围;如 :g/TODO/d、:g/{pat}/.,+2d、:g/{pattern}/yank A (把所有匹配行追加到寄存器) |
:[range1] v/{pattern}/[range2][cmd](或 global!) |
反转 global,对不含 pattern 的行执行;如 :v/href/d 只保留匹配行 |
:[range] s/{pattern}/{string}/[flags] |
替换;flags:g=全行、i=忽略大小写、c=逐个确认(y/n/a)、n=只计数;& 重复上次替换 |
Shell 命令
| 指令 |
说明 |
:! {cmd} |
执行 shell 命令 |
:shell |
临时启动交互式 shell,exit 返回 Vim |
:read !{cmd} |
执行 cmd,将标准输出插入光标下方 |
:[range] write !{cmd} |
以 range 为标准输入执行 cmd |
:[range]!{filter} |
用外部程序过滤指定 range |
命令行编辑
| 指令 |
说明 |
<Ctrl+b> / <Ctrl+e> 或 <Home> / <End> |
跳到命令文本开头 / 结尾 |
<Shift+←> / <Shift+→> |
命令行逐词跳转 |
寄存器
寄存器可以剪切(delete)、复制(yank,c已经分配给 change)、粘贴(put),也可以录制宏。
| 指令 |
说明 |
"{register} |
指定要使用的寄存器 |
"" |
无名寄存器(默认),x、s、d、c、y 等操作均写入此处 |
"_ |
黑洞寄存器,"_d{motion} 执行真正的删除,不覆盖无名寄存器 |
"0 |
复制专用寄存器,只有 y{motion} 才写入,比无名寄存器稳定 |
"+ |
系统剪贴板,插入模式下用 <Ctrl-r>+ 粘贴 |
"a-"z / "A-"Z |
有名寄存器,小写覆写,大写追加 |
"= |
表达式寄存器(可用作计算器) |
"% / "# / ". / ": |
只读:当前文件名 / 轮换文件名 / 上次插入文本 / 上次 Ex 命令;插入模式下 <Ctrl-r> 使用 |
:reg {register} |
查看寄存器内容 |
q{register}q |
录制空宏以清空有名寄存器 |
文件名修饰符
命令行中使用 "% 或 "# 时可以用文件名修饰符:
:p 绝对路径
:t 文件名
:r 去后缀
:e 后缀名
:h 目录路径
宏
| 指令 |
说明 |
q{register} |
开始录制(小写覆写,大写追加,如 qa / qA) |
q |
停止录制 |
@{register} |
回放一次 |
{N}@{register} |
回放 N 次(遇错即停,可指定较大次数) |
@@ |
重复上次回放 |
:put {register} |
把寄存器的宏内容倒出到 buffer(用于编辑宏) |
"{register}dd |
把 buffer 中编辑好的宏存入寄存器 |
Buffer / Window / Tab
Buffer
| 指令 |
说明 |
:bp[rev] / :bn[ext] |
上 / 下一个 buffer |
:bf[irst] / :bl[ast] |
第一个 / 最后一个 buffer |
:b[uffer] {n} |
跳转到编号 n 的 buffer |
:b[uffer] {name} |
根据名称跳转 |
:bd[elete] / :5,10bd |
删除 buffer / 删除编号 5~10 的 buffer |
:ls / :buffers |
列出所有打开的 buffer |
:cd % |
设置当前 buffer 的工作目录 |
Window
| 指令 |
说明 |
<Ctrl-w>s / <Ctrl-w>v |
水平 / 垂直切分窗口 |
<Ctrl-w>w |
在窗口间循环切换 |
<Ctrl-w>h/j/k/l |
切换到左 / 下 / 上 / 右的窗口 |
<Ctrl-w>c |
关闭活动窗口 |
<Ctrl-w>o |
关闭其他所有窗口 |
<Ctrl-w>= |
所有窗口等宽等高 |
<Ctrl-w>_ / <Ctrl-w>\| |
最大化活动窗口高度 / 宽度,前加数字可指定大小 |
Tab
| 指令 |
说明 |
:tabnew [filename] |
新建 tab |
:tcd |
设置当前 tab 的工作目录 |
gt / gT |
切换到下一个 / 上一个 tab |
{n}gt |
切换到第 n 个 tab |
:tabn {n} / :tabfirst / :tablast |
切换到第 n / 第一 / 最后一个 tab |
:tabm[ove] {n} |
移动 tab 到位置 n |
:tabc[lose] |
关闭当前 tab |
:tabo[nly] |
关闭其他 tab |
查找
| 指令 |
说明 |
/ / ? |
正向 / 反向查找 |
n / N |
下一个 / 上一个匹配 |
:set hlsearch / :set nohlsearch |
永久开启 / 关闭搜索高亮 |
:nohlsearch / :nohls / :hls! |
临时关闭搜索高亮 |
Quickfix
| 指令 |
说明 |
:cnext / :cprev / :cfirst / :clast |
跳转到下 / 上 / 第一 / 最后一项 |
:cc {N} |
跳转到第 N 项 |
:copen / :cclose |
打开 / 关闭 quickfix 窗口 |
细节与陷阱
Swap 文件
Vim 在编辑文件时会自动创建一个 .swap 文件(如 .foo.txt.swp),用于崩溃恢复。
触发场景与处理
| 场景 |
原因 |
处理方式 |
| 打开文件时提示 swap 已存在 |
上次编辑未正常退出,或同一文件被多处打开 |
R 恢复未保存内容;D 删除 swap;Q 放弃 |
| 同一文件被两个 Vim 实例打开 |
出现"Already opened by another program" |
找到另一个 Vim 进程关闭,或只读打开 :view |
| 误删文件后想恢复 |
swap 文件仍保留最后一次编辑状态 |
vim -r foo.txt 或在提示中按 R 恢复 |
常用命令
| 指令 |
说明 |
vim -r |
列出所有可恢复的 swap 文件 |
vim -r {file} |
从 swap 文件恢复指定文件 |
:recover |
在 Vim 内部执行恢复(等同于 vim -r) |
:set swapfile? |
查看当前 swap 是否启用 |
:set noswapfile |
临时关闭 swap(不推荐,崩溃无法恢复) |
:set directory={path} |
指定 swap 文件存放目录(避免工作目录被污染) |
最佳实践:恢复完成后,手动删除对应的 .swp 文件,或在 Vim 内执行 :!rm %:p:r.swp。
行为规律
- 添加括号时,左侧括号在内容两侧加空格,右侧括号不加空格。例如:
(foo) 用 [ 变为 [ foo ],用 ] 变为 [foo]。
- 字符查找时,f{c} 落在字符上;t{c} 落在字符前一格(till)
D, C, Y 分别等价于 d$, c$, y$
场景对比
重复上一次操作
| 场景 |
正向重复 |
反向重复 |
| Normal 修改 |
. |
u(撤销) |
| 字符查找 f/F/t/T |
; |
, |
搜索 / 和 ? 匹配 |
n |
N |
| 宏回放 |
@@ |
— |
| Ex 命令 |
@:,之后用 @@ |
— |
替换 :s |
&(重复上次替换) |
— |
跳到首 / 尾
| 场景 |
首 |
尾 |
| 文件行 |
gg |
G |
| 当前行 |
0 / ^ / g0 / g^ |
$ / g$ |
| 高亮选区 |
o(切换到另一端) |
O(块模式:切换对角) |
| 搜索匹配 |
ggn(从头开始跳) |
GN(从尾反向跳) |
易混淆
. 在 Normal 模式下表示重复上一次修改,在 Command 模式(Ex 地址)下表示当前行(如 :.,$d),在正则表达式中表示匹配任意单个字符
% 在 Command 模式下作范围地址时表示全文所有行(如 :%s/foo/bar/g),作文件名符号时表示当前文件路径(如 :w !sudo tee %),在 Normal 模式下表示跳到匹配的配对符号(括号、引号等)
b 在 Normal 模式下作 Motion 时表示向后移动一个单词,作文本对象时是 ) 的别名(如 dab=da))
* 在 Normal 模式下表示向后精确搜索光标所在词,在正则表达式中表示匹配前一个字符零次或多次
学习资料