Skip to content

03|Vim 编辑器

服务器上没有图形界面,SSH 终端里改配置只能靠命令行编辑器。Vim 是几乎所有 Linux 发行版的默认编辑器,但它的操作逻辑和 Notepad、VSCode 这类桌面编辑器截然不同——打开后不能直接打字,得先进入编辑模式。

第一次接触 Vim 的人,通常会卡在两个地方:打开文件后不知道怎么打字、不知道怎么退出。社区里甚至有"如何退出 Vim"被搜索数百万次的梗。本篇从模式机制讲起,依次介绍光标移动、编辑、搜索替换、可视模式、多文件操作和基础配置。

一、模式机制

Vim 的核心设计是三种模式——同一个按键在不同模式下含义完全不同。这是与普通编辑器最大的差异,也是上手最大的门槛。

模式进入方式用途
普通模式Esc移动光标、复制、粘贴、删除、执行命令
插入模式iaoIAO输入和修改文本
命令模式普通模式下按 :保存、退出、搜索替换、设置选项

打开文件后默认处于普通模式,不能直接打字。这是 Vim 与桌面编辑器最大的认知反差。

bash
vim /etc/hosts

执行上述命令后,屏幕显示了文件内容,但此时任何字母按键都不会输入字符,而是被解释为命令——按 i 进入插入模式才能开始打字。

救命准则:任何时候都能安全退出

任何时候只要按 Esc,就能回到普通模式。 这是 Vim 操作的安全基准。从普通模式出发,可以执行所有其他操作。

最基础的退出与保存命令:

vim
:w          " 保存
:q          " 退出
:wq         " 保存并退出
:q!         " 强制退出,丢弃所有修改
:x          " 等同于 :wq
ZZ          " 普通模式下按两次大写 Z,等同于 :wq

给初学者的安全退出步骤:不论按了什么键导致界面进入了未知状态,先按 Esc,再输入 :q! 回车——一定能退出,且不会保存任何意外修改。

二、光标移动

普通模式下的光标移动键:

按键移动方向
h j k l左 下 上 右
gg跳到文件开头
G跳到文件末尾
0当前行行首
^当前行第一个非空白字符
$当前行行尾
w下一个单词开头
b上一个单词开头
e当前/下一个单词结尾
%在配对的括号 ()[]{} 之间跳转

h j k l 在键盘上排成一行,熟练之后无需将手离开主键区,效率高于方向键。jk 的方向可以这样记忆:j 形状向下有钩子(下移),k 在键盘上位于 j 上方(上移)。现代终端中方向键通常也能正常工作,初学时使用方向键也可以,熟练后再切换到 hjkl

跳转到指定行号

vim
:120        " 跳到第 120 行
:$          " 跳到最后一行
120G        " 普通模式下输入数字+G 也能跳行

排查配置错误时,这个能力非常实用。例如 Nginx 启动失败时输出:

nginx: [emerg] unexpected ";" in /etc/nginx/nginx.conf:42

直接 vim /etc/nginx/nginx.conf 打开文件后,输入 :42 即可跳转到出错的行。

三、编辑操作

1. 进入插入模式

从普通模式进入插入模式的方式有多种,各自位置不同:

按键进入位置
i在光标前插入
a在光标后插入(append)
I跳到当前行行首并插入
A跳到当前行行尾并插入
o在下方新建一行并插入
O在上方新建一行并插入

oO 在追加配置行时高频使用:无需先移动到行尾再回车,直接 o 即可在下一行开始输入。

2. 普通模式下的删除与复制

普通模式下,无需进入插入模式即可完成删除、复制、粘贴:

命令效果
x删除光标处字符
dd删除整行(同时放入剪贴板)
dw删除一个单词
d$删除到行尾
yy复制整行
yw复制一个单词
p在光标后粘贴
P在光标前粘贴
u撤销上一步
Ctrl+r重做(取消撤销)

3. 数字前缀:批量执行

数字前缀可以让命令重复执行指定次数,这是 Vim 效率的核心机制之一:

vim
5dd         " 删除连续 5 行
3yy         " 复制连续 3 行
10x         " 删除 10 个字符
20j         " 向下移动 20 行

这种 "数字 + 操作" 的组合方式,远比反复按同一个键高效。复制 50 行用 50yy,删除一段大段配置用 100dd,都是一两秒完成。

四、搜索与替换

1. 搜索

普通模式下按 / 进入向下搜索,按 ? 向上搜索:

vim
/listen         " 向下搜索 listen
?error          " 向上搜索 error

跳转到匹配项后:

按键作用
n跳到下一个匹配
N跳到上一个匹配
*搜索光标所在的单词

查找配置文件中的某个指令(如 listenserver_nameproxy_pass)时,搜索是定位最快的方式。

2. 替换

替换使用 :s 命令,几种常用形态:

vim
:s/old/new/         " 替换当前行的第一个匹配
:s/old/new/g        " 替换当前行的所有匹配
:%s/old/new/g       " 替换整个文件的所有匹配(% 表示全文)
:%s/old/new/gc      " 替换前逐个确认(c = confirm)
:5,10s/old/new/g    " 只在第 5 到第 10 行替换

修改生产环境配置文件时,涉及 IP、域名、路径的替换应当带 c 参数。全文替换的影响范围远大于手工逐行修改——例如想把 10.0.0.1 替换为新 IP,但配置中还存在 10.0.0.10 这个完全不同的地址,默认的子串匹配会同时替换这两处,导致服务连接到错误的目标。

c 的交互式替换会在每次匹配时停下询问:

replace with new (y/n/a/q/l/^E/^Y)?
按键含义
y替换当前这一处
n跳过当前这一处
a替换所有(剩余的也全部替换)
q退出替换
l替换当前这一处后退出

精确匹配可以加上单词边界,避免误替换:

vim
:%s/\<10.0.0.1\>/192.168.1.1/gc

\<\> 是 Vim 正则中的单词边界,确保只匹配独立的 10.0.0.1,不会把 10.0.0.1010.0.0.100 也匹配进来。

五、可视模式:选中后批量操作

可视模式用于选中一段文本,选中之后再执行删除、复制、替换、注释等批量操作。

进入方式选择类型
v按字符选择
V按整行选择
Ctrl+v按列块选择(块可视模式)

进入可视模式后,使用 hjkl 或方向键扩展选区,然后:

  • d — 删除选中内容
  • y — 复制选中内容
  • c — 删除并进入插入模式
  • > — 选中行整体右缩进
  • < — 选中行整体左缩进

块可视模式批量注释

块可视模式 Ctrl+v 在批量注释多行时非常实用。下面演示如何把连续 5 行的开头加上 # 注释:

1. 把光标移到要注释的第一行的行首
2. 按 Ctrl+v 进入块可视模式
3. 按 4j 向下选中 5 行(当前行 + 下方 4 行)
4. 按 I(大写),光标跳到选中块的行首
5. 输入 #
6. 按 Esc 两次,所有选中行的开头都加上了 #

Esc 之后注释才会真正应用到所有行,中间任何时候按错都可以 u 撤销。

取消注释的逆操作:

1. 光标移到第一个 # 上
2. 按 Ctrl+v 进入块可视模式
3. 按 4j 选中下方 5 行的 # 字符
4. 按 d 删除选中块

这套操作适合临时注释测试,正式的配置变更仍然建议保留备份文件(cp -a 复制一份),u 撤销并不是可靠的回滚方案——Vim 进程异常退出或意外执行了 :wq 后,撤销历史就丢失了。

六、多文件与分屏

1. 同时打开多个文件

bash
vim nginx.conf default.conf

文件之间切换:

vim
:n              " 下一个文件
:prev           " 上一个文件
:ls             " 列出所有打开的 buffer
:b 2            " 切换到编号为 2 的 buffer
:bd             " 关闭当前 buffer

2. 分屏对照

修改配置时经常需要同时查看两个文件,例如对照默认配置改业务配置:

vim
:sp other.conf      " 水平分屏(上下)
:vsp other.conf     " 垂直分屏(左右)

分屏之间切换光标:

按键作用
Ctrl+w h/j/k/l切换到左/下/上/右窗口
Ctrl+w w在所有窗口间循环切换
Ctrl+w =让所有窗口大小相等
Ctrl+w q关闭当前窗口

七、基础配置:~/.vimrc

Vim 的个人配置存放在 ~/.vimrc服务器场景下的 Vim 配置应当保持简单——配置过于复杂、依赖外部插件,会导致换一台没有该 .vimrc 的机器时无法正常工作。运维场景的目标是"能舒服地修改配置文件",而不是把 Vim 改造成 IDE。

下面是一份适合服务器场景的基础配置:

vim
set number              " 显示行号
set tabstop=4           " Tab 显示为 4 个空格的宽度
set shiftwidth=4        " 自动缩进的宽度(>> 和 << 使用)
set expandtab           " 输入 Tab 时自动转换为空格
set ignorecase          " 搜索时忽略大小写
set smartcase           " 搜索内容包含大写字母时,自动切换为区分大小写
set hlsearch            " 高亮搜索结果
set incsearch           " 输入搜索内容时实时高亮
set ruler               " 在状态栏显示光标当前位置(行号、列号)
set showmatch           " 输入括号时高亮对应的另一半
syntax on               " 启用语法高亮

expandtab:避免 Tab 与空格混用

expandtab 这一项需要特别强调——Python 和 YAML 对缩进极度敏感,Tab 与空格混用会直接导致语法错误。修改 Kubernetes YAML、Ansible playbook、Python 脚本时,如果文件中混入 Tab 字符,排查问题时不容易发现是缩进格式问题。expandtab 强制将所有 Tab 输入转换为空格,从根本上避免这一问题。

可以通过 :set list 显式查看不可见字符,确认是否有混入的 Tab:

vim
:set list

输出中 Tab 显示为 ^I,空格为正常空白,行尾换行符为 $

文件类型相关的自动配置

针对不同文件类型自动应用不同的缩进规则:

vim
filetype plugin indent on        " 启用文件类型检测和对应的缩进规则

autocmd FileType yaml setlocal ts=2 sts=2 sw=2 expandtab
autocmd FileType python setlocal ts=4 sts=4 sw=4 expandtab

YAML 通常用 2 空格缩进,Python PEP 8 规范要求 4 空格,通过文件类型自动切换可以避免手动调整。

延伸学习资源