Skip to content

第 12 章 VIM 编辑器实战

Part 3 · 文本与编辑


引子

你在终端里需要改一个配置文件。也许是改一行 IP 地址,也许是改一行编译选项。

你输入 vim config.txt,屏幕上出现了一片内容——然后你按方向键,屏幕上开始输出字母;你按退格键,什么都没删掉;你试着输入文字,终端滴一声报错。

这是无数人的 Vim 初体验:进去了,出不来了。

Vim 的设计哲学和现代编辑器完全相反——它不追求「打开就能用」,它追求「熟练之后效率碾压一切」。

从「进不去出不来」到「不想再用别的编辑器」,中间有一条路。这章带你走完它。


背景与动机

有一件事你可能还没遇到过,但迟早会:你通过 SSH 远程连接到一块嵌入式开发板,板子上没有图形界面,没有桌面,连鼠标都不存在。这时候你需要改一行启动参数,或者编辑一个网络配置文件。

你能用什么?

Gedit?没有桌面环境。Notepad++?那是 Windows 的。VSCode?开发板的内存连它的启动画面都加载不了。

你需要的是一个能在纯终端里工作的编辑器。

Linux 世界里,能完成这个任务的主流选择有三个:nanovimemacsnano 最简单,打开就能用,但功能有限——处理几百行的配置文件时,没有语法高亮和快速跳转会让你非常难受。emacs 功能最强大,但学习曲线甚至比 Vim 还陡。而 vim——几乎所有 Linux 发行版都预装它(或者至少预装它的精简版 vi),从 Ubuntu 桌面到最小的嵌入式 BusyBox 环境,你总能在某个角落找到它。

学会 Vim 不是为了炫技。它是你在没有图形界面的环境里,唯一可靠的文本操作手段。

一个现实场景:在 imx-forge 项目中,你会频繁通过串口或 SSH 连接到 i.MX 开发板,修改 U-Boot 环境变量、编辑设备树源文件、调整内核启动参数——这些全在终端里完成。到时候,Vim 就是你唯一的武器。


概念层

模式:Vim 的灵魂

这一节表面上在讲「怎么用 Vim」,但真正的问题是:为什么 Vim 的按键逻辑和所有现代编辑器都不一样?

答案是一个词:模式(mode)

在记事本或 VSCode 里,你按 a,屏幕上就出现字母 a。输入即所见。Vim 不是这样。在 Vim 里,同一个按键在不同时刻有完全不同的含义——取决于你当前处于哪种模式。

类比 1/3 —— 赛车的挡位

你可以把 Vim 想象成一辆手动挡赛车。同一脚油门踩下去,挂一挡和挂五挡,效果完全不同。不是油门变了,而是挡位决定了油门的含义

Vim 的模式就是挡位:

  • 普通模式(Normal mode):空挡滑行。你踩油门(敲键盘)不会让车加速(不会输入文字),但你可以打方向、调后视镜、观察路况——在 Vim 里,这些操作叫移动光标、删除行、复制粘贴。
  • 插入模式(Insert mode):挂挡踩油门。你按 a,屏幕上出现字母 a。这才是真正「打字」的地方。
  • 命令行模式(Command-line mode):设置导航。你停下车,在导航仪上输入目的地——在 Vim 里,这是保存文件、退出、搜索替换等全局操作。

Vim 启动后默认进入普通模式。这就解释了引子里那一幕:你打开文件,开始打字——但 Vim 认为你在下达命令,不是在输入文字。所以按键变成了乱七八糟的操作,终端还会对无效操作发出警告音。

三种模式之间的切换路径

普通模式 ──(i / a / o 等)──► 插入模式
普通模式 ◄──(ESC)──────────── 插入模式
普通模式 ──(:  /  ?)──────► 命令行模式
普通模式 ◄──(ESC / 回车)──── 命令行模式

所有切换都经过普通模式。普通模式是枢纽,插入模式和命令行模式是分支——你不会直接从插入模式跳到命令行模式,必须先回普通模式再转。

类比 2/3 —— 揭示距离

赛车的类比到这里需要修正。手动挡换挡是为了适应不同速度——一挡起步,五挡巡航。但 Vim 切换模式不是为了「快慢」,而是为了分离操作类型

真实的 Vim 设计逻辑是:你编辑文件时,大部分时间不应该花在打字上——你花更多时间在阅读、导航、调整结构。所以默认模式不是「输入」,而是「操作」。只有当你真正要打字时,才切换到插入模式。

这个反直觉的设计决策,正是 Vim 高效的根源。新手觉得 Vim 麻烦——「打个字都要先按 i?」;老手觉得其他编辑器才麻烦——「我只想删一行,为什么要点三下鼠标?」。这个认知反转,就是理解 Vim 的关键门槛。

关于模式的数量,有一个需要澄清的细节:Vim 官方定义了七种基本模式(Normal、Visual、Select、Insert、Command-line、Ex、Terminal-Job)和七种附加模式。这些模式里,Ex 模式几乎不会用到,Terminal-Job 模式只在终端窗口内使用。日常开发中,掌握普通模式、插入模式、命令行模式这三种就能覆盖 95% 的操作。Visual 模式(用于选择文本块)我们会在实践层中补充。


实践层

4.1 安装与第一次点火

Ubuntu 22.04/24.04 默认预装了 vim.tiny——一个精简版 Vim。它能用,但很多功能被裁掉了(语法高亮、撤销历史、插件支持等)。先用完整版学习:

bash
$ sudo apt install vim
# 安装完成后验证版本
$ vim --version | head -3
# 预期输出(版本号可能略有不同)
VIM - Vi IMproved 9.1 (2024 Jan 02, compiled Jun 02 2026 22:00:15)
Included patches: 1-16, 647, 678, 697
Modified by team+vim@tracker.debian.org

装好之后,创建一个练习目录和测试文件:

bash
$ mkdir -p ~/vim-lab
$ cd ~/vim-lab
$ vim hello.txt

回车之后你看到的界面:一个几乎全空的屏幕,光标在左上角闪烁,左侧有波浪线 ~ 标记空行,底部有一行状态信息。

现在——不要动。观察一下你面前的屏幕。

这就是普通模式。Vim 在等你下达命令,不是等你打字。

4.2 第一次打字与保存退出

在普通模式下按 i 键。

看屏幕底部——如果出现了 -- INSERT ---- 插入 --,恭喜,你已经切换到插入模式了。

现在你可以正常打字:

Hello, Vim!
This is my first file edited with Vim.
Vim is powerful.

打完之后,按 ESC 键。底部的 -- INSERT -- 消失。你回到了普通模式。

保存并退出——在普通模式下,输入 :wq 然后按回车:

bash
:wq
# Vim 保存文件并退出,你回到终端提示符

:wq 是三个东西拼在一起的:: 进入命令行模式,w 代表写入(write),q 代表退出(quit)。

验证文件内容:

bash
$ cat hello.txt
# 预期输出
Hello, Vim!
This is my first file edited with Vim.
Vim is powerful.

如果你把文件改得一塌糊涂想重来,可以用 :q!——强制退出不保存。这个命令是新手的好朋友,记下来:

bash
:q!       # 强制退出,丢弃所有修改
:wq       # 保存并退出
:w        # 只保存,不退出

⚠️ 踩坑预警:Ctrl+S 综合征

你可能习惯性地想按 Ctrl+S 保存。千万别按。 在 Linux 终端里,Ctrl+S 不是保存,而是发送 XOFF 信号——它会冻结你的终端。一旦按下,终端看起来像死了一样,什么按键都没反应。

解冻方法:按 Ctrl+Q(发送 XON 信号),终端立刻恢复。

这件事坑了我无数次。后来我养成了一个习惯:在 Vim 里保存永远用 :w,不用任何快捷键。

4.3 普通模式——导航与手术刀

普通模式是 Vim 的主战场。你在这里做两件事:移动光标操作文本

重新打开刚才的文件:

bash
$ vim hello.txt

基本移动——用 h j k l

按键方向记忆方式
h最左边的键 → 左移
jj 的尾巴朝下 → 下移
kk 的竖笔朝上 → 上移
l最右边的键 → 右移

现代 Vim 也支持方向键,但 hjkl 的意义在于:你的右手不需要离开主键盘区。当你编辑几百行的配置文件时,这种效率差距是实实在在的。

进阶移动

bash
# 行内跳转
0          # 跳到行首(数字零)
$          # 跳到行尾
^          # 跳到行首第一个非空字符

# 文件级跳转
gg         # 跳到文件第一行
G          # 跳到文件最后一行
5G         # 跳到第 5 行

# 翻页
Ctrl+f     # 向下翻一页(Forward)
Ctrl+b     # 向上翻一页(Backward)

这里有一个重要的认知模型:Vim 把文本操作设计成了「动词 + 名词」的结构。你告诉 Vim 做什么(动词),以及对什么范围做(名词)。这不是随意的快捷键堆砌——它是一套语言。

删除操作

bash
x          # 删除光标处的单个字符
dd         # 删除(剪切)整行
3dd        # 删除从当前行开始的 3 行
dw         # 删除从光标到下一个单词开头的部分
d$         # 删除从光标到行尾的内容

dd 不是真的「删除」——它是「剪切」。被 dd 掉的内容存在 Vim 的寄存器(register)里,可以随时用 p 粘贴回来。

复制与粘贴

bash
yy         # 复制(yank)整行
3yy        # 复制从当前行开始的 3 行
p          # 在光标后粘贴
P          # 在光标前粘贴(大写 P)

撤销与重做

bash
u          # 撤销上一步操作
Ctrl+r     # 重做(redo,撤销的撤销)

来实战一下。打开 hello.txt,光标移到第三行:

bash
$ vim hello.txt
# 1. 按 dd —— 第三行消失了
# 2. 按 p —— 它又出现在了当前行之后
# 3. 按 u —— 撤销,文件恢复原样

这三步让你体验了 Vim 最核心的操作循环:操作 → 粘贴 → 撤销。一旦这个循环刻进肌肉记忆,你会发现编辑文本的速度有了质的提升。

类比 3/3 —— 回到那辆赛车

现在你应该明白了:普通模式不是「什么都不能做的空挡」——它是你可以操纵整辆车的驾驶舱。dd 是方向盘一样干脆利落的操控,yy 是抄起一份地图揣兜里,p 是把地图摊开在面前。插入模式?那只是你偶尔停下车来装货的地方。老司机大部分时间都在驾驶舱里,而不是货厢。

4.4 搜索与替换

搜索——在普通模式下按 /

bash
/Vim
# 按回车,光标跳到第一个匹配处
# 按 n 跳到下一个匹配
# 按 N 跳到上一个匹配

Vim 会高亮所有匹配的文本。如果高亮太刺眼,按 :noh(no highlight)可以临时关闭。

替换——在命令行模式下使用 :s(substitute):

bash
# 替换当前行第一个匹配
:s/old/new/

# 替换当前行所有匹配
:s/old/new/g

# 替换整个文件所有匹配
:%s/old/new/g

# 替换整个文件所有匹配,逐个确认
:%s/old/new/gc
# Vim 会逐个高亮匹配,问你 y(替换)/ n(跳过)/ q(退出)

实战——把 hello.txt 里的 Vim 全部替换成 VIM

bash
$ vim hello.txt
# 进入普通模式后输入:
:%s/Vim/VIM/g
# 预期:所有 "Vim" 被替换为 "VIM"
# 底部显示替换数量,例如:3 substitutions on 2 lines

搜索和替换在处理配置文件时极为常用。比如你接手一块开发板,需要把所有旧 IP 地址 192.168.1.100 改成新的 192.168.1.200——一条 :%s 命令就搞定了。

4.5 可视模式——选择文本块

之前所有操作都是「告诉 Vim 范围,Vim 自己选中」。但有时候你想自己选一块文本再操作——这就是可视模式(Visual mode)。

bash
v          # 字符可视模式(按字符选择)
V          # 行可视模式(按行选择)
Ctrl+v     # 块可视模式(按矩形列选择)

进入可视模式后,用 hjkl 或方向键移动光标,选中的文本会高亮。然后你可以对选中内容执行操作:d 删除、y 复制、: 进入命令行模式执行替换等。

块可视模式(Ctrl+v)在批量注释代码时特别实用:选中一列,按 I(大写 i)输入注释符,然后按两次 ESC,选中的每一行都会被加上注释。

4.6 你的第一个 .vimrc

每次打开 Vim 都要手动配置?Vim 有一个启动配置文件:~/.vimrc。在这个文件里写的每一行,Vim 启动时都会自动执行。

先创建配置文件:

bash
$ vim ~/.vimrc

i 进入插入模式,输入以下内容:

vim
" 显示行号
set number

" 开启语法高亮
syntax on

" 设置缩进为 4 个空格
set tabstop=4
set shiftwidth=4
set expandtab

" 搜索时忽略大小写
set ignorecase
" 但如果搜索词包含大写字母,则区分大小写(智能大小写)
set smartcase

" 搜索时实时高亮匹配
set hlsearch
" 增量搜索——边输入边匹配
set incsearch

" 高亮当前光标所在行
set cursorline

" 开启鼠标支持(可选——在终端里可以用鼠标滚轮翻页)
set mouse=a

按 ESC 回到普通模式,:wq 保存退出。

然后用 Vim 打开任意文件试试。行号出来了,语法高亮有了,搜索也能实时匹配了——这些小小的配置会让你的 Vim 体验提升一个档次。

进阶提示:如果你日常在桌面环境下工作,VSCode 配合 Vim 插件(如 VSCodeVim)可以兼顾图形界面的舒适和 Vim 的键位效率。但记住,在 SSH 连接开发板的时候,你面对的只有裸 Vim——所以基本功不能丢。


练习题

走到这里,模式切换应该已经刻进肌肉记忆了——或者还没有,那就更需要练。

下面几道题难度递进,建议先不看提示独立做,卡住了再翻。

练习 12.1 ⭐(理解)

用 Vim 打开一个文件,不输入任何文字,直接退出。有哪些方法?如果文件被修改了但没有保存,直接 :q 会发生什么?

练习 12.2 ⭐⭐(应用)

创建一个文件 shopping.txt,输入 10 行任意内容。然后用 Vim 完成以下操作:

  1. 删除第 3 到第 5 行(共 3 行)
  2. 把删除的内容粘贴到文件末尾
  3. 把所有空格替换为下划线 _

提示:先跳到第 3 行(3G),然后 3dd 删除 3 行,再跳到末尾(G)按 p 粘贴。替换用 :%s/ /_/g

练习 12.3 ⭐⭐⭐(思考)

为什么 Vim 的默认模式是普通模式而不是插入模式?这背后反映了一种什么样的编辑哲学?假设你来设计一个终端编辑器,你会采用同样的设计吗?为什么?


本章回响

这一章真正在建立的东西只有一个:模式这个概念。

它看起来只是 Vim 的操作方式——按 i 打字,按 ESC 停下来,按 :wq 走人。但「模式」背后是对编辑行为的重新分类:浏览和操作是两种完全不同的任务,不应该用同一套按键同时处理。这个分类让每个按键在最常用的模式下拥有了最优映射——普通模式下 dd 删一行,比任何 GUI 编辑器的「选中→右键→删除」都快,正是因为普通模式不需要顾虑「这个键是不是要输入字符」。

还记得开头那个场景吗——你打开 Vim,按方向键出现乱码,按退格没反应,终端滴一声报错,进去了出不来?现在你知道了:Vim 把你扔进普通模式,是因为它认为你会花更多时间在导航和操作上——而你的手指还停在记事本的思维模式里。这不是 Vim 的设计「反人类」,而是它做了一个诚实的假设:编辑不只是打字。理解了这一点,那些看似怪异的按键设计就都说得通了。

下一章我们会进入文本处理的领域——用 sedawksort 等工具批量处理日志和配置文件。到时候你会发现,Vim 处理的是「手动编辑」,而那些工具处理的是「自动化编辑」。两者共享同一片土壤:文本。


← 上一章下一章 →

Built with VitePress