当你已经习惯了 i 进入插入模式、dd 删除一行、/ 搜索关键词之后,可能会觉得 Vim 也不过如此------无非是一个需要记忆快捷键的编辑器罢了。但真正的 Vim 大师会告诉你:你还在用手动操作,而我已经让编辑器自己写代码了。
Vim 的高级之处,不在于你记住了多少个快捷键,而在于你能否让编辑器替你完成重复的工作。这正是宏(Macro)、寄存器(Register)和标记(Mark)存在的意义:
- 寄存器 是你的多重剪贴板,不止能存文本,还能存命令、搜索模式,甚至是 Vim 脚本的表达式的计算结果。
- 标记 是你的书签系统,让你在数百上千行的文件中瞬间穿梭,定位到函数定义、修改位置、或任何你标记过的角落。
- 宏 是键盘操作的"录像机",你操作一遍,Vim 替你重复一千遍。
这三者单独使用已经足够强大,而当你学会将它们组合起来------比如在宏中调用标记跳转,或将寄存器内容作为宏的指令------你将真正体验到什么叫"编辑器的魔法"。
本文将从实战出发,由浅入深地讲解这三个核心概念,并提供大量可以直接上手的示例。无论你是想摆脱重复劳动的开发者,还是希望进一步提升效率的 Vim 老用户,相信都能从中获益。
1. 寄存器( Registers )
寄存器是 Vim 的剪贴板系统,用于存储、提取文本。
常用寄存器类型
| 寄存器 | 用途 |
|---|---|
| "" | 默认寄存器(d/y/x/p 默认使用) |
| "0 | 上次 yank 的文本(不包含删除) |
| "1-"9 | 删除历史(1 最新,9 最旧) |
| "- | 小删除(少于一行) |
| "a-"z | 命名寄存器(可指定使用) |
| "+ | 系统剪贴板 |
| "* | 选择剪贴板(X11) |
| "/ | 上次搜索模式 |
| ": | 上次命令 |
| ". | 上次插入的文本 |
寄存器操作
vim
" 使用命名寄存器
"ayy " 将当前行存入寄存器 a
"ap " 粘贴寄存器 a 的内容
" 追加到寄存器(大写字母)
"Ayy " 将当前行追加到寄存器 a
" 查看寄存器
:reg " 显示所有寄存器
:reg a b " 显示寄存器 a 和 b
" 系统剪贴板
"+yy " 复制到系统剪贴板
"+p " 从系统剪贴板粘贴

2. 标记( Marks )
标记用于记录位置,方便快速跳转。
标记类型
| 标记 | 范围 | 用途 |
|---|---|---|
| a-z | 当前文件 | 用户自定义标记 |
| A-Z | 全局(跨文件) | 跨文件跳转 |
| 0-9 | 全局 | viminfo 自动保存 |
| ' | 当前文件 | 上次编辑位置 |
| " | 当前文件 | 上次退出位置 |
| [ ] | 当前文件 | 上次修改的开始/结束 |
| < > | 当前文件 | 上次可视选择的开始/结束 |
标记操作
vim
" 设置标记
ma " 在当前行设置标记 a
mA " 设置全局标记 A
" 跳转到标记
'a " 跳转到标记 a 所在行(列首)
`a " 跳转到标记 a 的精确位置(行列)
" 查看标记
:marks " 显示所有标记
:marks a b " 显示指定标记
:delmarks a " 删除标记 a
:delmarks! " 删除所有当前文件标记
实用标记技巧
vim
" 快速返回上次编辑位置
'' " 跳回上次位置(两个单引号)
`` " 跳回上次精确位置
" 跳转到最后修改位置
g; " 跳转到上一个修改位置
g, " 跳转到下一个修改位置
" 关联标记与寄存器(删除 / 剪切)
"ad' " 从当前位置删除到标记 a
"ay' " 从当前位置复制到标记 a
3. 宏( Macros )
宏录制一系列操作并重复执行。
基础宏操作
vim
" 录制宏
qa " 开始录制到寄存器 a ( q + 寄存器名)
... " 执行操作
q " 停止录制
" 执行宏
@a " 执行寄存器 a 中的宏
@@ " 重复上一个执行的宏
" 多次执行
3@a " 执行宏 a 三次
" 查看宏
:reg a " 查看宏 a 的内容
宏录制技巧
vim
" 1. 录制时使用相对移动
qaj10jq " 跳转 10 行,确保可重复
" 2. 录制前定位到行首
0qayyPjq " 复制并粘贴,然后下一行
" 3. 使用搜索定位
qafoo<CR>yyq " 搜索 foo 并复制
" 4. 录制结束前移动到下一目标
qacommandjq " 执行后移动到下一行(便于 @@ 重复)
高级宏技巧
vim
" 编辑宏
:let @a='ihello<ESC>' " 直接设置宏内容
:let @a=substitute(@a, 'old', 'new', 'g') " 修改宏
" 递归宏(小心使用)
qq@qq " 录制 q 并立即调用自身,直到出错停止
" 宏配合数字寄存器
:let i=1
qqA, <ESC>@aq " 宏调用自身(小心无限循环)
" 更好的重复方式
qa...q " 录制
100@a " 执行 100 次(出错自动停止)

4. 三者协同实战
场景 1 :为每行添加序号
假设文件内容:
text
apple
banana
cherry
vim
" 方法一:宏 + 寄存器
0i1. <ESC>
"ay$ " 复制当前行到寄存器 a
j
"ap " 粘贴第 1 行内容
q
" 执行前将数字改为 2 ,然后 @@ 重复
" 方法二:更优雅的方式
:let i=1 | g/^/s//\=i . '. ' / | let i+=1
" 或使用命令行宏
:let i=1 | normal qq0i<C-R>=i<CR>. <ESC>:let i+=1<CR>j@aq
场景 2 :格式化 CSV 数据
text
name,age,city
john,25,nyc
jane,30,la
vim
" 录制宏将逗号替换为表格分隔符
qa
:s/,/ | /g
:s/^/| /
:s/$/ |/
j
q
" 对剩余行执行
4@a
场景 3 :跨文件批量修改
vim
" 1. 记录操作宏
qb
i/* <ESC>A */<ESC> " 添加注释标记
:wn " 写入并切换到下一个文件
q
" 2. 录制查找并跳转的宏
qc
:cn " 到下一个匹配
@b " 执行修改
q
" 3. 对匹配项执行
:grep "old_text" *.txt " 生成匹配列表
:cfdo normal @c " 对所有匹配文件执行宏
场景 4 :快速跳转与编辑组合
vim
" 设置文件结构标记
ma " 函数开始
mb " 关键位置 1
mc " 关键位置 2
" 快速在标记间复制 / 移动
'ayt( " 从标记 a 复制到下一个括号
'd'b " 从当前位置删除到标记 b
" 宏中使用标记
qd
`a " 跳转标记 a
yy " 复制
`b " 跳转标记 b
p " 粘贴
q

5. 效率技巧总结
| 操作 | 命令 | 说明 |
|---|---|---|
| 重复修改 | . | 重复上次修改(简单情况) |
| 重放宏 | @@ | 快速重放 |
| 批量执行 | 100@a | 自动停于错误 |
| 宏编辑 | :let @a='...' | 直接修改宏内容 |
| 寄存器引用 | <C-R>a | 插入模式下粘贴寄存器 |
| 表达式寄存器 | <C-R>= | 插入模式下计算表达式 |
| 视觉模式执行宏 | :'<,'>normal @a | 对选定行执行宏 |
| 全局执行宏 | :%normal @a | 对所有行执行宏 |
记忆口诀
- 寄存器 :"a 存取,"+ 系统通,"0 专门存 yank
- 标记 :m 记位置,' 飞过去, ` 精确落点
- 宏 :q 录 @ 放,@@ 重复唱,100@ 批量放
这些高级功能组合使用,能将编辑效率提升数倍。熟能生巧,建议每天练习一个场景。