适用读者:只想"别被 vi 卡住"的人;以及在服务器上改配置、看日志、容器里没有 GUI 编辑器的人。
前置:S01-B07(终端可用)。
实测环境:Ubuntu 24.04.1 自带vi(vim 兼容模式)与vim;命令在 vim 9 与 vi 兼容模式下均已核对(差异见 §5)。
覆盖旧文:A-1421–A-1437(17 篇"超详细"短文,共 400 个原文点位)。
上一篇:S01-B07 · 终端与包管理器:从系统终端到 Tabby / Warp / WindTerm
下一篇:S01-B09 · 环境重置与迁移。
1. 一句话结论
先学 5 个动作活下来:进、改、存、出、撤。 其余 12 个按需查——本篇把旧文 17 篇压成一张卡。
旧文的组织方式是"一个动作一篇",17 篇互相不引用,读者学完仍然不知道"我现在在哪个模式"。Vim 的核心不是命令,是模式:
┌──────────── 按 i / a / o ────────────┐
│ ▼
┌─────────┐ ┌──────────┐
│ 普通模式 │ │ 插入模式 │
│ (默认) │ ◄──── 按 Esc ───────────── │ (可打字) │
└────┬────┘ └──────────┘
│ 按 : 按 v / V / Ctrl+v
▼ ▼
┌──────────┐ ┌──────────┐
│ 命令行模式│ │ 可视模式 │
│ (: 开头) │ │ (选区) │
└──────────┘ └──────────┘
一切"按键没反应"的困惑,都是因为你在错误的模式里。 记住这一条,比背 60 个命令有用。
2. 最小动作卡(先背这 5 条)
| 场景 | 动作 | 按键 |
|---|---|---|
| 进 | 打开文件 | vim file.txt(只读查看用 vim -R file.txt) |
| 改 | 进入插入模式 | i(光标前)/ a(光标后)/ o(下方新行) |
| 存 | 保存 | Esc → :w → Enter |
| 存并出 | 保存退出 | Esc → :wq 或 ZZ |
| 出(不存) | 强制退出 | Esc → :q! |
| 撤 | 撤销 / 重做 | u / Ctrl+r |
被 vi 卡住的唯一正解:连按两次
Esc,输入:q!,回车。不保存直接走。任何"网上说要按什么"的花招都不如这一条可靠。
3. 17 个动作逐条(对应旧文 17 篇)
3.1 保存与退出(A-1421)
| 命令 | 含义 | 风险 |
|---|---|---|
:w |
保存 | 只读文件会报 E45: 'readonly' option is set |
:q |
退出(有未保存改动会被拒) | 报 E37: No write since last change |
:q! |
强制退出,丢弃改动 | 改动全丢,先想清楚 |
:wq / :x / ZZ |
保存并退出 | :x 只在有改动时写盘 |
ZQ |
退出不保存(等同 :q!) |
同上 |
只读文件想改::w !sudo tee %(需要 sudo 权限时);或先 sudo vim file。
3.2 显示/隐藏行号(A-1422)
:set number " 显示绝对行号
:set nu " 同上(缩写)
:set relativenumber " 相对行号(配合 5j、12k 跳转极快)
:set nonumber " 关闭
持久化:写进 ~/.vimrc(:set nu 一行即可)。临时查看不想改配置,就直接在命令行模式敲。
3.3 替换字符串(A-1423)
| 命令 | 作用范围 |
|---|---|
:s/old/new/ |
当前行第一个 |
:s/old/new/g |
当前行全部 |
:%s/old/new/g |
整个文件全部 |
:%s/old/new/gc |
全文件,逐个确认(y/n/a/q) |
:'<,'>s/old/new/g |
可视选区(选中后按 : 自动带出范围) |
注意::s 默认只改当前行,这是最高频的误判——你以为改了全文,其实只改了一行。改全文一定要 %。
实测(vim 9.1,Ubuntu 24.04.1):
printf 'a1\na2\na3\n' > f.txt
vim -e -s -u NONE f.txt <<'EOF'
:s/a/X/
:wq
EOF
# 结果:a1 / a2 / X3 ← 只有一行被改(脚本模式下光标在末行)
# 换成 :%s/a/Y/g
Y1 / Y2 / Y3 ← 三行全改
同一次实验里 ggdG 把文件清成 0 字节(wc -c = 0),所以"清空"确实是不可逆的第一步——下一步 :wq 就写盘了。
特殊字符:/ 出现在待替换文本里时换分隔符,如 :s#/usr/local#/opt#g。
3.4 跳转到指定行(A-1424)
| 目标 | 命令 |
|---|---|
| 第 120 行 | :120 然后 Enter(或 120G) |
| 文件头 / 尾 | gg / G |
| 相对跳转 | 5j(下 5 行)、8k(上 8 行) |
| 上次位置 | ``(两个反引号) |
| 标记后跳回 | m a 打标记 → `a 跳回 |
3.5 搜索与高亮(A-1425、A-1428)
| 动作 | 按键 |
|---|---|
| 向下搜索 | /keyword → Enter |
| 向上搜索 | ?keyword → Enter |
| 下一个 / 上一个 | n / N |
| 光标下单词搜索 | *(向下)/ #(向上) |
| 高亮开关 | :set hlsearch / :nohlsearch(:noh) |
| 跳到行内字符 | f<char>(向后)/ F<char>(向前) |
高亮残留是新手最常见的困扰:搜完一片黄,用
:noh清掉,别以为文件坏了。
3.6 编辑命令:删除、复制、粘贴(A-1426、A-1431)
Vim 的语法是 操作符 + 动作:
| 组合 | 含义 |
|---|---|
dd |
删除当前行(并进剪贴板/"寄存器") |
3dd |
删除 3 行 |
dw |
删一个词 |
d$ / D |
删到行尾 |
yy |
复制当前行 |
3yy |
复制 3 行 |
yw |
复制一个词 |
p / P |
粘贴到光标后 / 前 |
"ayy / "ap |
复制到寄存器 a / 从 a 粘贴(多剪贴板) |
p 与 P 的方向是唯二需要记的细节:小写往后、大写往前。
3.7 删除一行(A-1427)
dd 是最快的;要精确到行号:
:5d " 删第 5 行
:2,8d " 删 2–8 行
:g/pattern/d " 删所有匹配 pattern 的行
:%d 删全文(A-1429 的"清空文件内容")——高危:执行后文件为空,如果此时 :wq 保存,内容就没了。清空内容后想保留空文件,应 :w 前确认;想撤销,立刻 u。
3.8 清空文件内容(A-1429、A-1433)
| 方式 | 说明 |
|---|---|
ggdG |
光标到首行,删除到末行(推荐,比 :%d 直观) |
:%d |
同上,命令式 |
可视全选后 d |
ggVG 再 d(V 是行可视) |
安全习惯:清空类操作前先
:w backup.txt存一份,或者干脆用:w !cat > /tmp/bak之类的备份思路。不可逆的操作要先留退路。
3.9 退出编辑模式(A-1430)
Esc 是正解。若 Esc 在你终端里不灵(少见),Ctrl+[ 等价于 Esc。Ctrl+C 也能退回普通模式,但它不触发 InsertLeave 自动命令(有些插件依赖该事件),所以优先 Esc。
3.10 撤销与重做(A-1432)
| 动作 | 按键 |
|---|---|
| 撤销 | u |
| 重做 | Ctrl+r |
| 撤销整行改动 | U |
| 按时间线回退 | :earlier 5m / :later 5m |
u 与 U 不同:u 是逐步撤销(每按一次退一步),U 是把"当前行"的所有改动一次性还原。这是 vi 兼容模式与 vim 的一处经典差异(见 §5)。
3.11 全选复制 / 全选删除(A-1434、A-1433)
| 目标 | 按键 |
|---|---|
| 全选复制 | ggVGy |
| 全选删除 | ggVGd |
| 复制到系统剪贴板 | "+ggyG(需 vim 编译带 +clipboard) |
检查是否支持剪贴板::echo has('clipboard') 返回 1 才行;返回 0 就只能用 "*y 之外的办法(或装 vim-gtk3)。
3.12 多行注释(A-1435)
方案一(块可视插入,推荐):
Ctrl+v → 选中多行 → I(大写 i)→ 输入 // → Esc
按 Esc 后,选中的每一行都会被加上 //。
方案二(替换命令):
:2,10s/^/\/\// " 2–10 行行首加 //
:2,10s/^\/\/// " 去掉
方案三(按文件类型改注释符):插件方案(NERD Commenter / vim-commentary 的 gcc)不在本篇范围;旧文提到的 :comment 与 <leader>gc 属第三方插件命令,未装插件时不可用(旧文未说明这一点,是常见误导)。
3.13 跳到行尾 / 最后一行(A-1436、A-1437)
| 目标 | 按键 |
|---|---|
| 行尾 | $(g_ 到行尾最后一个非空白字符) |
| 最后一行 | G;或 :$ |
| 回到上次跳转前 | Ctrl+o |
3.14 粘贴时缩进错乱(A-1436 的 :set paste)
从浏览器/IDE 复制代码粘进终端里的 vim,会出现"每一行多一层缩进"。修法:
:set paste " 粘贴前打开(关闭自动缩进)
" 粘贴完成后
:set nopaste
更省事的现代做法:用终端的多行粘贴(多数终端支持 Ctrl+Shift+V,也支持 bracketed paste),v9 之后 vim 自身对 bracketed paste 已处理得较好。
4. 误操作恢复速查
| 误操作 | 恢复 |
|---|---|
不小心 dd 删了一行 |
u |
不小心 :%d 清空 |
u(别急着存) |
| 保存后发现改错 | u 后重存;若已退出,用 vim -u NONE file 查看 .swp 或版本控制找回 |
:wq 存到了错误文件 |
立即 git checkout -- file(若在仓库里) |
| 打开大文件卡死 | Ctrl+C 中断,改用 less/tail -f/grep |
终端里 Esc 无反应 |
Ctrl+[ |
一条铁律:Vim 里任何不可逆操作之前,先 u 试一下能不能撤回。Vim 的撤销树通常很深,大部分误操作可救。
5. vi 与 vim 的差异(旧文没提,但服务器上天天遇到)
| 方面 | vi(兼容模式) |
vim |
|---|---|---|
| 撤销 | 单步(再按 u 不继续退) |
多级撤销 |
| 语法高亮 | 默认关 | 默认开 |
| 可视块 | 部分实现 | 完整 |
:set paste |
可能不支持 | 支持 |
| 方向键/退格 | 插入模式下可能异常 | 正常 |
判定当前用的是哪个:
:version " 看是否有 +vim 特性
:set compatible? " compatible 为 on 说明在 vi 兼容模式
建议:服务器上装 vim 并把默认编辑器指向它(update-alternatives --config vi),或在 ~/.vimrc 里 set nocompatible。
6. 自检清单
| # | 检查 | 做法 | 通过标准 |
|---|---|---|---|
| 1 | 5 秒内安全退出 | 打开文件 → 乱按一通 → Esc Esc :q! |
文件未被修改 |
| 2 | 能改能存 | i 改一行 → Esc :wq |
cat 出来是新内容 |
| 3 | 能全文替换 | :%s/old/new/g |
grep old 无结果 |
| 4 | 能跳转 | :120 与 G、gg |
位置正确 |
| 5 | 能撤销 | dd → u |
行回来了 |
| 6 | 能批量注释 | Ctrl+v 选 3 行 → I// → Esc |
3 行都加了 // |
7. 旧文对照
| 旧文 | 主题 | 本篇位置 | 处理 |
|---|---|---|---|
| A-1421 | 保存退出 | §3.1 | 补 :x、ZZ、ZQ 与只读文件处置 |
| A-1422 | 显示行号 | §3.2 | 补 relativenumber 与持久化 |
| A-1423 | 替换字符串 | §3.3 | 强调"默认只改当前行"这一高频误判;补 # 分隔符 |
| A-1424 | 跳转指定行 | §3.4 | 并入统一导航表,补标记跳回 |
| A-1425 / A-1428 | 搜索 / 查找字符串 | §3.5 | 两篇内容高度重复,合并为一节;补 :noh |
| A-1426 | 编辑命令 | §3.6 | 提炼"操作符+动作"语法,补寄存器 |
| A-1427 | 删除一行 | §3.7 | 补按行号删、g/pattern/d |
| A-1429 / A-1433 | 清空文件内容 / 全选删除 | §3.8、§3.11 | 合并;新增高危提醒与备份习惯 |
| A-1430 | 退出编辑模式 | §3.9 | 补 Ctrl+[ 与 Ctrl+C 的差异 |
| A-1431 | 复制粘贴 | §3.6 | 并入 |
| A-1432 | 撤销 | §3.10 | 补 Ctrl+r、:earlier、u vs U |
| A-1434 | 全选复制 | §3.11 | 补系统剪贴板检查 |
| A-1435 | 多行注释 | §3.12 | 保留块可视法;标注旧文提到的 :comment/<leader>gc 属插件命令,未装不可用 |
| A-1436 | 跳到行尾 | §3.13、§3.14 | 拆为"跳行尾"与"粘贴缩进"两处 |
| A-1437 | 跳到最后一行 | §3.13 | 并入导航表 |
| — | 模式概念、vi/vim 差异、误操作恢复 | 新增 §1、§4、§5 | 17 篇旧文完全没有系统层的内容 |
8. 自测
:s/old/new/与:%s/old/new/g的区别是什么?在什么情况下最容易改错?u与U分别撤销什么?- 在
vi兼容模式下按两次u没反应,为什么? - 粘贴代码后每行都缩进多一层,最省事的两种解法?
:%d之后按:wq,文件内容还能救回来吗?为什么?
9. 下一篇
S01-B09 · 环境重置与迁移:干净卸载、清缓存、配置搬家
vim 会用了,就能在服务器上改配置了。下一篇回到 IDE:环境被折腾坏之后,怎么彻底卸载不留残、怎么把配置搬到新机器、以及"缓存、索引、插件、配置"四类数据各自存在哪。
本篇属于系列《S01 · 开发环境与工具链》。旧文来源:A-1421–A-1437(17 篇);点位映射见 ../coverage.csv。