5月27日 14:58

Vim 的寄存器到底有几种,各自用在什么场景?

为什么你的 Vim 粘贴总是不对

你一定遇到过这种情况:复制了一行代码,删掉另一行,再粘贴时发现粘贴的是刚删掉的内容,而不是你复制的那行。这不是 bug,这是 Vim 寄存器机制在起作用——大多数操作都默认写入同一个无名寄存器,后进来的把前面的覆盖了。

Vim 并不是只有一个剪贴板,它有十几种寄存器,每种都有明确的用途。搞清楚它们,复制粘贴不再踩坑,还能用寄存器做宏录制、表达式计算、跨程序复制等高级操作。

无名寄存器("")——默认的垃圾桶

每次执行 yankdeletechange 等操作,内容都会自动写入无名寄存器 ""。普通模式下按 p 粘贴,用的就是它。

问题在于,dd 删除一行和 yy 复制一行都会覆盖 ""。所以你复制之后做了一次删除,粘贴出来的就是删除的内容。

这不代表原来的内容丢了——它还在数字寄存器 "0 里。所以下次遇到"粘贴不对",先试 "0p,大概率就是你想要的内容。

命名寄存器("a–"z)——手动管理的 26 个抽屉

命名寄存器是最常用的一类,用法简单:操作前加 "寄存器名

vim
"ayy " 将当前行复制到寄存器 a "ap " 粘贴寄存器 a 的内容 "bdw " 删除一个单词并存入寄存器 b

这样你可以在 a 里存一段代码,b 里存另一段,随时按 "ap"bp 取出来,互不干扰。

大写字母是追加,不是覆盖

如果寄存器 a 里已经有内容,"ayy 会覆盖它。但用大写 "Ayy 则是追加:

vim
"ayy " 覆盖写入寄存器 a "Ayy " 追加到寄存器 a 末尾

这在收集分散内容时很有用——比如把文件中多个位置的函数签名逐行追加到同一个寄存器,最后一次性粘贴。

数字寄存器("0–"9)——自动记录的历史栈

数字寄存器不需要手动指定,Vim 自动维护:

  • "0:最近一次 yank 的内容,不会被 delete 覆盖
  • "1:最近一次 delete 或 change 的内容
  • "2:倒数第二次 delete 的内容
  • …以此类推到 "9

注意 "0 是 yank 专用,只有 y 操作才会更新它。ddx 只会更新 "1"9,不会碰 "0

实际场景:你 yy 复制了一行,然后 dd 删了几行,想粘贴最初复制的那行——"0p 就是答案。

只读寄存器——Vim 自动填入的元信息

四个只读寄存器,你只能读取,不能手动写入:

寄存器内容典型用法
"%当前文件名插入文件名:插入模式下 Ctrl+r %
".最后插入的文本重复上次输入:插入模式下 Ctrl+r .
":最后执行的 Ex 命令再次执行上条命令:@:
"/最后的搜索模式替换时复用::%s//替换内容/g

其中 "/ 在替换命令里特别实用——:%s//new/g 等价于 :%s/上次搜索的词/new/g,省去重新输入搜索内容。

黑洞寄存器("_)——删除但不留痕迹

"_dd 删除一行,但不会存入任何寄存器,无名寄存器和数字寄存器都不会被更新。

什么时候用?当你删掉的内容不需要粘贴,又不想污染寄存器历史的时候。比如清理大量注释行,用 "_dd 逐行删除,你的 "0 仍然保存着之前 yank 的内容,不受影响。

表达式寄存器("=)——在插入模式做计算

在插入模式下按 Ctrl+r =,Vim 会在命令行提示你输入一个表达式,计算结果直接插入光标处。

vim
" 插入模式下: Ctrl+r =3600*24" 插入 86400 Ctrl=r =strftime('%Y-%m-%d')" 插入当前日期

也可以在命令里引用变量或函数返回值,适合需要动态插入内容的场景。

系统剪贴板("+ 和 "*)——和外部程序互通

Vim 默认不与系统剪贴板交互,需要通过 "+"* 寄存器:

  • "+yy:复制当前行到系统剪贴板
  • "+p:从系统剪贴板粘贴

"+"* 在 Windows 和 macOS 上行为一致,都指向系统剪贴板。在 Linux 上有区别:"+ 是 CLIPBOARD(Ctrl+C/V),"* 是 PRIMARY(鼠标选中即复制,中键粘贴)。

如果你希望每次 yank/paste 自动使用系统剪贴板,可以设置:

vim
set clipboard=unnamedplus

这样普通 yyp 就直接操作系统剪贴板了。

:reg——查看所有寄存器内容

忘了某个寄存器里存了什么?用 :reg:registers 查看全部,也可以指定只看某几个:

vim
:reg " 查看所有非空寄存器 :reg a b 0 " 只看寄存器 a、b、0 :reg / : " 查看搜索模式和上次 Ex 命令

输出格式是寄存器名 + 内容,内容中的换行用 ^J 表示。调试宏或确认寄存器状态时经常用到。

宏与寄存器——本质上是同一套机制

Vim 的宏录制就是把按键序列存进命名寄存器。qa 开始录制到寄存器 a,再按 q 停止,@a 回放。

这意味着:

  1. 录制的宏可以用 :reg a 查看,内容就是一串按键字符
  2. 你可以把宏内容粘贴出来编辑,改好再 yank 回去——修改宏不需要重新录制
  3. 用大写追加可以往宏里追加指令:qA 追加录制到 a 宏末尾

编辑宏的流程:

vim
:reg a " 先看看宏 a 里的内容 "ap " 把宏内容粘贴到缓冲区 " 编辑这一行按键序列 "ayy " 重新 yank 回寄存器 a

这种可编辑性是 Vim 宏区别于简单"录制回放"的关键——出错了不用重来,改一行就行。

把寄存器用起来

寄存器不是 Vim 里"知道就好"的冷知识,它直接影响日常编辑效率。几个建议:

  • 复制重要内容时指定命名寄存器("ayy),避免被后续删除覆盖
  • 需要干净删除时用黑洞寄存器("_dd),保持寄存器历史干净
  • 复制粘贴跨程序时显式用 "+y / "+p,不要依赖自动剪贴板设置
  • 录制宏后用 :reg 检查内容,复杂宏直接编辑比重新录制更高效

Vim 的寄存器体系看起来种类多,但核心逻辑就是一条:每次操作前加 "寄存器名,就是指定目标寄存器;不加,就是无名寄存器。记住这个规律,其他的都是在此基础上的分类和特例。

标签:Vim