服务端阅读 05月27日 14:58
Vim 的寄存器到底有几种,各自用在什么场景?
为什么你的 Vim 粘贴总是不对你一定遇到过这种情况:复制了一行代码,删掉另一行,再粘贴时发现粘贴的是刚删掉的内容,而不是你复制的那行。这不是 bug,这是 Vim 寄存器机制在起作用——大多数操作都默认写入同一个无名寄存器,后进来的把前面的覆盖了。Vim 并不是只有一个剪贴板,它有十几种寄存器,每种都有明确的用途。搞清楚它们,复制粘贴不再踩坑,还能用寄存器做宏录制、表达式计算、跨程序复制等高级操作。无名寄存器("")——默认的垃圾桶每次执行 yank、delete、change 等操作,内容都会自动写入无名寄存器 ""。普通模式下按 p 粘贴,用的就是它。问题在于,dd 删除一行和 yy 复制一行都会覆盖 ""。所以你复制之后做了一次删除,粘贴出来的就是删除的内容。这不代表原来的内容丢了——它还在数字寄存器 "0 里。所以下次遇到"粘贴不对",先试 "0p,大概率就是你想要的内容。命名寄存器("a–"z)——手动管理的 26 个抽屉命名寄存器是最常用的一类,用法简单:操作前加 "寄存器名。"ayy " 将当前行复制到寄存器 a"ap " 粘贴寄存器 a 的内容"bdw " 删除一个单词并存入寄存器 b这样你可以在 a 里存一段代码,b 里存另一段,随时按 "ap 和 "bp 取出来,互不干扰。大写字母是追加,不是覆盖如果寄存器 a 里已经有内容,"ayy 会覆盖它。但用大写 "Ayy 则是追加:"ayy " 覆盖写入寄存器 a"Ayy " 追加到寄存器 a 末尾这在收集分散内容时很有用——比如把文件中多个位置的函数签名逐行追加到同一个寄存器,最后一次性粘贴。数字寄存器("0–"9)——自动记录的历史栈数字寄存器不需要手动指定,Vim 自动维护:"0:最近一次 yank 的内容,不会被 delete 覆盖"1:最近一次 delete 或 change 的内容"2:倒数第二次 delete 的内容…以此类推到 "9注意 "0 是 yank 专用,只有 y 操作才会更新它。dd 和 x 只会更新 "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 会在命令行提示你输入一个表达式,计算结果直接插入光标处。" 插入模式下:Ctrl+r =3600*24↵ " 插入 86400Ctrl=r =strftime('%Y-%m-%d')↵ " 插入当前日期也可以在命令里引用变量或函数返回值,适合需要动态插入内容的场景。系统剪贴板("+ 和 "*)——和外部程序互通Vim 默认不与系统剪贴板交互,需要通过 "+ 或 "* 寄存器:"+yy:复制当前行到系统剪贴板"+p:从系统剪贴板粘贴"+ 和 "* 在 Windows 和 macOS 上行为一致,都指向系统剪贴板。在 Linux 上有区别:"+ 是 CLIPBOARD(Ctrl+C/V),"* 是 PRIMARY(鼠标选中即复制,中键粘贴)。如果你希望每次 yank/paste 自动使用系统剪贴板,可以设置:set clipboard=unnamedplus这样普通 yy 和 p 就直接操作系统剪贴板了。:reg——查看所有寄存器内容忘了某个寄存器里存了什么?用 :reg 或 :registers 查看全部,也可以指定只看某几个::reg " 查看所有非空寄存器:reg a b 0 " 只看寄存器 a、b、0:reg / : " 查看搜索模式和上次 Ex 命令输出格式是寄存器名 + 内容,内容中的换行用 ^J 表示。调试宏或确认寄存器状态时经常用到。宏与寄存器——本质上是同一套机制Vim 的宏录制就是把按键序列存进命名寄存器。qa 开始录制到寄存器 a,再按 q 停止,@a 回放。这意味着:录制的宏可以用 :reg a 查看,内容就是一串按键字符你可以把宏内容粘贴出来编辑,改好再 yank 回去——修改宏不需要重新录制用大写追加可以往宏里追加指令:qA 追加录制到 a 宏末尾编辑宏的流程::reg a " 先看看宏 a 里的内容"ap " 把宏内容粘贴到缓冲区" 编辑这一行按键序列"ayy " 重新 yank 回寄存器 a这种可编辑性是 Vim 宏区别于简单"录制回放"的关键——出错了不用重来,改一行就行。把寄存器用起来寄存器不是 Vim 里"知道就好"的冷知识,它直接影响日常编辑效率。几个建议:复制重要内容时指定命名寄存器("ayy),避免被后续删除覆盖需要干净删除时用黑洞寄存器("_dd),保持寄存器历史干净复制粘贴跨程序时显式用 "+y / "+p,不要依赖自动剪贴板设置录制宏后用 :reg 检查内容,复杂宏直接编辑比重新录制更高效Vim 的寄存器体系看起来种类多,但核心逻辑就是一条:每次操作前加 "寄存器名,就是指定目标寄存器;不加,就是无名寄存器。记住这个规律,其他的都是在此基础上的分类和特例。