系列 · Linux · 第 9 篇

Linux(九):Vim 编辑器精要

不靠死记快捷键学 Vim —— 而是掌握它的语法:模式(mode)、操作符(operator)+ 动作(motion)、文本对象(text object)。一份实用、新手友好的指南,附带一周刻意练习计划。

大多数人放弃 Vim,是因为试图死记硬背快捷键——这完全走错了方向。Vim 本质上是一门小型语言:只要掌握它的语法——操作符 + 动作(operator + motion)——你就能表达任意编辑意图,从此再也不用打开速查表。本指南将带你掌握日常使用频率高达 80% 的 Vim 核心功能,并说明剩下的 20% 如何自然地从同一套基础规则中推导出来。


你将学到什么#

  • 一个核心思想:模式(mode) 加上 可组合的操作(operator + motion)
  • 覆盖绝大多数场景的少量动作、文本对象和操作符
  • 文件操作、搜索与替换、宏(macro)、标记(mark)、寄存器(register)
  • 缓冲区(buffer)、窗口(window)与标签页(tab)——这是初学者最容易搞错的概念模型
  • 一份极简的 .vimrc 配置,以及一份为期一周的刻意练习计划,助你建立肌肉记忆

前置知识#

  • 任意终端(Vim 几乎预装于所有类 Unix 系统)
  • 愿意接受大约一周的“变慢期”——这是必经阶段

核心思想:模式 + 极简语法#

Vim 的四种常用模式

Vim 围绕一个简单循环运转:

  1. 移动到你想修改的位置(一个 motion);
  2. 选定作用范围(由 motion 隐式决定,或在 Visual 模式中显式选择);
  3. 应用一个 operator —— 删除(delete)、更改(change)或复制(yank)。

一旦这个循环变成你的本能反应,你就不再“记住按键”,而是开始“说 Vim”。

你真正会用到的四种模式#

  • Normal 模式 —— 导航与执行命令。Vim 启动即在此模式,你大约 80% 的时间都应花在这里。
  • Insert 模式 —— 输入文字。把它当作一次短暂的“离线”:进入、输入一小段内容、立刻退出。
  • Visual 模式 —— 选中文本(字符级 / 行级 / 块级)。
  • Command-line 模式 —— 所有以 : 开头的命令(保存、搜索替换、设置),或 /?(正向/反向搜索)。

Replace 模式(R)也存在,但多数人只是误触进入。如果你发现打字突然开始覆盖已有字符,立刻按 Esc —— 你已意外进入 Replace 模式。

最重要习惯:每次输入完毕,立即按 Esc。空闲时,务必停留在 Normal 模式——那里每个按键都是命令。

操作符(operator)与动作(motion)—— Vim 的语法#

一条 Vim 命令读起来就像一句微型英文句子:

1
[count] operator motion

操作符(operator) —— 做什么

Op含义
d删除
c更改(删除 + 进入 Insert)
y复制(yank)
>右移缩进
<左移缩进
=自动缩进

动作 / 文本对象(motion / text object) —— 作用多大范围

  • w / b —— 下一 / 上一单词
  • 0 / ^ / $ —— 行首 / 行首首个非空白字符 / 行尾
  • gg / G / {n}G —— 文件开头 / 文件末尾 / 第 n
  • iw / ip / i" —— 单词内部 / 段落内部 / 双引号内字符串

现在来组合:

  • dw —— 删除一个单词
  • d$ —— 删除至行尾
  • ciw —— 更改当前单词(inner word)
  • yip —— 复制整个段落
  • 3dw —— 删除接下来三个单词

这就是全部游戏规则。只需熟记五个操作符、十几种动作,你就能比在大多数 GUI 编辑器中编辑得更快。


移动:跳跃,而非爬行#

Vim 动作速查表

上方速查表值得打印一次,之后就再也不用看了。比起死记按键,理解其分类逻辑更重要:

  • 字符级 (h j k l):仅当别无选择时才用。若发现自己连按 j 超过三次,说明该换更高效的 motion。
  • 单词级 (w b e):按词跳转。
  • 行级 (0 ^ $):行首、行首非空格处、行尾。
  • 文件级 (gg G {n}G):文件顶部、底部、指定行。
  • 屏幕级 (Ctrl-f, Ctrl-b, Ctrl-d, Ctrl-u):整页或半页滚动。
  • 搜索级 (/pattern, ?pattern, n, N, *, #):在代码中导航最快的方式,永远是搜索关键词,而不是手动滚动。

有两个 motion 特别值得强调,因为它们与操作符配合堪称完美:

  • f{char} 跳转到本行下一个 {char}t{char} 跳转到它之前的位置。所以 df, 会删除光标到下一个逗号(含逗号)之间的所有内容——编辑参数列表时极为常见。
  • % 在匹配的括号间跳转。从左括号 ( 开始按 d%,即可删除整个括号包裹的表达式。

编辑:删除、更改、复制、粘贴#

删除(delete)#

键位效果
x删除光标下的单个字符
dd删除当前整行
d{motion}删除 motion 覆盖的范围
D删除光标至行尾(等价于 d$

更改(change:删除 + 进入 Insert)#

键位效果
cc替换整行
c{motion}替换 motion 覆盖范围并进入 Insert 模式
C更改至行尾(等价于 c$

复制(yank)#

键位效果
yy复制当前整行
y{motion}复制 motion 覆盖的范围
Y复制至行尾

粘贴(paste)#

  • p —— 在光标之后粘贴(对行级 yank,则粘贴在当前行下方
  • P —— 在光标之前粘贴(对行级 yank,则粘贴在当前行上方

撤销与重做(undo / redo)#

  • u —— 撤销
  • Ctrl-r —— 重做
  • :earlier 5m / :later 30s —— 在撤销中时间旅行(没错,Vim 的撤销是树状结构,不是栈!)

“剪切”就是删除#

Vim 没有独立的 cut 命令。删除操作本身就会把文本放入寄存器,因此移动一行只需:dd → 移动光标 → p

重复点(dot)命令 .#

. 会重复你上一次的变更操作。例如执行 ciw + 输入 host + Esc 后,移动到另一个单词,按 . 就能同样将其改为 host。点命令将 operator-motion 语法升华为一键宏;请养成让每个编辑操作都支持 . 重复的习惯。


文本对象(text object)—— 按语义编辑,而非按位置#

文本对象:按语义编辑

文本对象是初学者最容易忽略、而高手天天都在用的功能。你无需手动定位边界,只需命名一个语义单元

  • i(inner)表示不包含定界符(如引号、括号)
  • a(around)表示包含定界符
对象含义示例
iw / aw单词内部 / 单词及其周围空格ciw 更改一个单词
is / as句子内部 / 句子及其周围标点dis 删除一个句子
ip / ap段落内部 / 段落及其周围空行yip 复制一个段落
i" / a"双引号内部 / 包含双引号ci" 重写字符串字面量
i' / a'单引号内部 / 包含单引号di' 删除单引号字符串
i( / a(圆括号内部 / 包含圆括号da( 删除括号及其中内容
i{ / a{花括号内部 / 包含花括号ci{ 重写代码块
i[ / a[方括号内部 / 包含方括号di[ 删除数组字面量
it / atHTML 标签内部 / 包含标签cit 重写标签内容

光标无需位于边界上——ci" 从引号内部任意位置、甚至就在引号上都能生效。这才是重点:你不再想“先选中再操作”,而是直接“对这个东西执行操作”。


搜索与替换 —— 安全第一#

/pattern 正向搜索,?pattern 反向搜索;nN 用于遍历匹配项。

替换遵循经典的 ed/sed 语法:

1
2
3
4
5
:s/old/new/        " 当前行首次匹配
:s/old/new/g       " 当前行所有匹配
:%s/old/new/g      " 全缓冲区所有匹配
:10,40s/old/new/g  " 仅第 10 至 40 行
:%s/old/new/gc     " 全局替换,每处都提示确认(y/n/a/q)

比直接运行 :%s/old/new/g 更安全的工作流:

  1. 先运行 /old,用 n 逐个确认匹配是否符合预期。
  2. 再运行 :%s//new/gc —— 空 pattern 会复用上次搜索,c 则让 Vim 对每个匹配弹出 y / n / a / q 提示。
  3. 完成后运行 :noh 清除高亮。

搜索模式内还可使用以下标志:

  • \c 忽略大小写,\C 强制区分大小写
  • \<word\> 全词匹配(word boundary)
  • \v “very magic” 模式 —— 更多字符被当作正则元字符(更接近 Perl/PCRE)

宏(macro)—— 不离开 Vim 即可自动化#

宏是 Vim 中 ROI(投入产出比)最高的“进阶”功能:它能把任何重复性编辑变成一次录制、无限回放。

1
2
3
4
5
6
qa            " 开始录制到寄存器 a
... edits ... " 执行你想重复的操作(移动 + 操作)
q             " 停止录制
@a            " 回放宏
@@            " 回放上一个宏
20@a          " 回放 20 次

写出健壮宏的关键,在于确保每次动作都能从一个已知起点重复。常见模式:每次迭代都以 0(行首)开始,以 j(下一行)结束。这样连续回放在多行上才能保持同步。


寄存器(register)—— 拥有三十个插槽的剪贴板#

每次 yank 或 delete 都会进入一个 register。Vim 提供多个寄存器:

  • "" —— 未命名寄存器(默认;最近一次 delete/yank 所在)
  • "a"z —— 命名寄存器,由你主动填充
  • "0"9 —— yank/delete 历史("0 是最近一次 yank,"1 是上上次……)
  • "+"* —— 系统剪贴板(需 Vim 编译时启用 +clipboard;可用 vim --version | grep clipboard 检查)
  • "_ —— 黑洞寄存器。发往此处的内容直接消失;当你想删除但不覆盖未命名寄存器时非常有用

用法如下:

1
2
3
4
5
"ayy   " 将当前行复制到寄存器 a
"ap    " 从寄存器 a 粘贴
"+yy   " 复制到系统剪贴板
"+p    " 从系统剪贴板粘贴
:reg   " 查看所有寄存器内容

进阶技巧:当你准备粘贴后,又要立刻删除其他内容(这会污染剪贴板),可在 delete 前加 "_ —— 例如 "_dd 删除当前行,但不会影响你刚 yank 的内容。


标记(mark)—— 跨文件或跨项目的书签#

1
2
3
ma     " 在光标位置设置标记 a
'a     " 跳转到标记 a 所在行
`a     " 跳转到标记 a 的精确位置(含列)

小写字母标记(az)仅在当前 buffer 有效;大写字母标记(AZ)是全局的,跨文件依然存活——非常适合“稍后回来处理”。

Vim 还会自动维护几个特殊标记:

  • ` ` —— 上次跳转前的位置
  • `. —— 最后一次编辑的位置
  • `^ —— 最后一次处于 Insert 模式的位置
  • `" —— 上次关闭此文件时的位置

Visual 模式 —— 尤其是 Visual Block(块选择)#

三种类型:

  • v —— 字符级选择
  • V —— 行级选择
  • Ctrl-v —— 块级(矩形)选择。这是杀手级功能。

Visual Block 解决了“在二十行上同时编辑同一列”这一难题——在大多数其他编辑器中,这需要正则或宏:

1
2
3
注释 5 行:      Ctrl-v  jjjj  I  #  Esc
为 10 行末尾加 ;: Ctrl-v  9j    A  ;  Esc
删除 4 行的某一列: Ctrl-v  jjj   d

通用流程:进入块模式 → 垂直扩展选区 → 按 I(在块前插入)或 A(在块后追加)→ 输入一次 → 按 Esc → Vim 自动将变更应用到每一行。


文件、窗口、分屏、标签页#

文件操作(command-line 模式)#

命令效果
:w保存(write)
:q退出(quit)
:wq / :x / ZZ保存并退出
:q!强制退出,丢弃未保存更改
:e {file}打开文件
:saveas {file}另存为
:!cmd调用 shell(如 :!ls, :!git status

分屏(split)#

命令效果
:sp {file}水平分屏
:vsp {file}垂直分屏
Ctrl-w h/j/k/l在分屏间切换
Ctrl-w =均分各分屏尺寸
:close / :only关闭当前分屏 / 关闭除当前外所有分屏

缓冲区(buffer) vs 窗口(window) vs 标签页(tab)#

这是初学者最常混淆的概念模型。请慢慢读一遍:

概念是什么常用命令
Buffer加载进内存的一个文件:ls, :b {name}, :bnext, :bprev
Window显示某个 buffer 的一个视口:split, :vsplit, Ctrl-w 移动命令
Tab一组 window 的布局:tabnew, gt, gT

一个文件只要被打开,就立刻成为一个 buffer,哪怕当前没有任何 window 显示它。两个 window 可以显示同一个 buffer(比如同时查看长文件的开头和结尾)。Tab 并非浏览器式的“打开的文件”,而是已保存的窗口布局

交换文件(swap file)#

若你尝试打开一个 Vim 正在别处编辑的文件,或 Vim 曾异常崩溃,你会看到 .swp 警告。Vim 在询问:是否要从崩溃中恢复未保存的更改?还是直接继续?若不需要恢复,删除孤立的 .swp 文件即可消除警告:

1
find . -name ".*.swp" -delete

一份极简、安全的 .vimrc#

Vim 的文件组织结构

只需设置几个默认值,Vim 就会变得舒适自然。暂勿堆砌插件——从这份配置起步:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
" ---- 显示设置 ----
set number
set relativenumber
set cursorline
syntax on

" ---- 缩进设置 ----
set expandtab
set tabstop=4
set shiftwidth=4

" ---- 搜索设置 ----
set ignorecase
set smartcase     " 仅当搜索词含大写字母时才区分大小写
set hlsearch
set incsearch

" ---- 易用性 ----
set hidden        " 切换 buffer 时无需先保存
set scrolloff=4   " 光标上下保留 4 行上下文
set wildmenu      " command-line 模式下支持 Tab 补全

" ---- 保存时:自动清除行尾空格 ----
autocmd BufWritePre * :%s/\s\+$//e

保存为 ~/.vimrc,重启 Vim 即可生效。(Vim 无守护进程,配置只在启动时读取。)

若你使用 Neovim,对应配置位于 ~/.config/nvim/init.vim(或 init.lua,若使用 Lua 配置)。


常见工作流 —— 搜索替换与多文件编辑#

你每天都会用到的两种工作流

掌握基础后,你大部分 Vim 时间都将花在这两类流程上。图中已逐步演示;下方纯文本版方便你边练边复制粘贴。

项目级搜索与替换

1
2
3
/oldName             " 先遍历确认匹配是否正确
:%s//newName/gc      " '' 复用上次搜索,c = 每处都确认
:noh                 " 清除残留高亮

多文件编辑

1
2
3
4
5
:e src/api.py        " 打开文件 1
:vsp src/main.py     " 垂直分屏打开文件 2
:sp README.md        " 水平分屏打开文件 3
Ctrl-w h/j/k/l       " 在窗口间跳转
:ls   :b api         " 列出所有 buffer,按名称片段快速切换

常见陷阱与脱困方法#

1. 粘贴代码出现过度缩进。 Vim 的自动缩进会重新缩进每行粘贴内容。解决方法:

1
2
3
:set paste       " 临时禁用自动缩进
" ... 粘贴 ...
:set nopaste

更优方案:用 "+p 从系统剪贴板粘贴,Vim 会将其视为一个整体块处理。

2. 打字突然覆盖原有字符。 你误按了 R(或终端的 Insert 键),进入了 Replace 模式。按 Esc 即可退出。

3. 每次打开文件都弹出 swap file 警告。 上次 Vim 会话未正常退出。删除孤立的 swap 文件(见第 10 节 ),或在 Neovim 中运行 :checkhealth

4. u 撤销结果不符合预期。 Vim 的撤销是树状结构,而非线性栈。用 :earlier 5m / :later 30s 按时间轴浏览编辑历史。

5. 无法退出 Vim: 经典难题。从任意模式,先按 Esc 确保回到 Normal 模式,再输入 :q! + Enter 强制退出(不保存),或 :wq 保存并退出。


Vim 还是 Neovim?#

两者皆优秀。按实际需求选择:

  • 继续用 Vim:若你主要在远程服务器或容器中编辑(Vim 几乎预装于所有环境),或你并不需要 LSP / 现代插件生态。
  • 切换到 Neovim:若你需要内置 LSP(自动补全、跳转定义、诊断)、Lua 配置、异步插件,以及更活跃的社区演进。

你可在两者间无缝切换——编辑器命令完全一致,仅配置方式与插件层不同。


为期一周的刻意练习计划#

你掌握 Vim 的方式,和掌握任何语言一样:强制自己在固定周期内坚持使用它,哪怕初期比平时更慢。

第 1–2 天 —— 仅限这些键。 hjkl, w, b, 0, ^, $, dd, dw, ciw, /, :%s。所有编辑必须用这些完成。你会很慢。这正是目的所在。

第 3–4 天 —— 加入文本对象。 强迫自己用 ciw, ci", ci(, dap,彻底告别手动选中。此时 Vim 开始真正变快。

第 5 天 —— 加入宏: 只要发现重复操作(≥3 次),立刻录制:qaq@a

第 6 天 —— 加入分屏与缓冲区。 停止新开终端标签页。改用 :vsp, :sp, :b, Ctrl-w 导航。

第 7 天 —— 自定义配置。 现在 修改 .vimrc。加入第 11 节 的设置,再添加一两条个人映射。至少再忍一周,不要装插件。

经过这一周,Vim 的语法将刻入你的手指。此后,你学到的每一个新技巧(新 motion、新 text object)都只是自然嵌入你已有的语法体系。


总结#

  1. 模式是你的朋友: Normal 是家;Insert 只是短暂离线。
  2. 牢记 operator + motion。 d + w = 删除单词。一切皆为句子。
  3. 善用文本对象: ciw, di", yip 永远优于手动选中。
  4. 先搜索,再编辑: /foo 后接 cw,永远快过滚动查找。
  5. . 重复简单编辑: 对简单变更,. 是最快的一键宏。
  6. 用宏处理复杂重复: qaq20@a
  7. 深度掌握少数关键 motion。 w/b, 0/$, gg/G, f{char}, /, % 覆盖绝大多数导航场景。
  8. 早期切忌过度定制: 先学默认行为;再加映射;最后才考虑插件。
  9. 用 buffer 和 split,而非新开终端窗口。
  10. 坚持刻意练习一周: 之后,Vim 不再“难用”,而开始“飞快”。

当语法真正融入你的手指,Vim 就不再是你“操作”的工具,而成为一门你能流利言说的文本编辑语言。


下一步去哪里#

  • vimtutor —— 在终端中直接运行。30 分钟,Vim 自带。
  • Drew Neil 的《Practical Vim》—— 从入门到精通的最佳书籍。
  • Vim Adventures —— 浏览器游戏,寓教于乐学 motion。
  • Vim Golf —— 竞技型最小按键数挑战;进阶技巧绝佳训练场。
本系列

Linux 9 篇

  1. 01 Linux(一):使用基础
  2. 02 Linux(二):文件权限 —— rwx、chmod、chown 与超越它们的机制
  3. 03 Linux(三):磁盘管理
  4. 04 Linux(四):软件包管理
  5. 05 Linux(五):用户管理
  6. 06 Linux(六):系统服务管理
  7. 07 Linux(七):进程与资源管理 —— 从 top 到 cgroups
  8. 08 Linux(八):文件操作深入解析
  9. 09 Linux(九):Vim 编辑器精要 当前

读有所得?

GitHub 关注我 → 新文周更

GitHub