服务器运维

Vim 编辑器是什么:三种模式与修改配置文件实操

Vim 编辑器是 vi 的增强版,在没有图形界面的 Linux 服务器上用来查看和修改配置文件。它靠模式工作:打开文件时处于普通模式,按 i 进入插入模式输入文字,按 Esc 回到普通模式,再输入 :wq 保存退出。记住这个循环,大多数配置就能改完。

作者 顶联产品团队发布于 7 分钟阅读

Vim 编辑器是 Linux 和类 Unix 系统里的终端文本编辑器,名字是 Vi IMproved 的缩写,意思是“改进版的 vi”。它不用鼠标和菜单,全部靠键盘操作,并且用“模式”来区分你按下的键是在输入文字还是在执行命令。服务器通常没有图形界面,改 /etc 下的配置文件、看一段日志、写个小脚本,用的都是它。只想先把文件改完,记住这个循环就够了:vim 文件名 打开,按 i 开始输入,改完按 Esc,再输入 :wq 回车保存退出;改乱了不想保存,按 Esc 后输入 :q! 回车。

vim 是什么意思:vi、Vim 与精简版的关系

vi 是 Bill Joy 在 1976 年前后为 BSD Unix 编写的全屏编辑器,后来被写进 POSIX 标准,所以几乎每个类 Unix 系统都有一个叫 vi 的命令。Vim 由 Bram Moolenaar 在 1991 年发布,起初是 Amiga 上的一个 vi 仿制品,功能越加越多,名字也从 Vi IMitation 改成了 Vi IMproved。Bram 于 2023 年去世,Vim 此后由社区维护者继续发布新版本。

两者的主要区别:

对比项 传统 vi Vim
撤销 只能撤销最近一次修改,再按 u 会把撤销本身撤回 多级撤销,u 逐步后退,Ctrl+r 重做
语法高亮 没有 按文件类型着色,shell、YAML、nginx 等都能识别(需要完整版)
可视模式 没有 v、V、Ctrl+v 按字符、按行、按列选中
插入模式下的方向键 不能用 可以直接移动光标
分屏与对比 没有 :sp、:vsp 分屏,vimdiff 对比两个文件
配置与扩展 ~/.exrc,选项很少 ~/.vimrc,支持 Vim script 和插件

现在大多数发行版里输入 vi,启动的其实是某种精简版 Vim,不同系统差别不小:

系统 输入 vi 时实际运行的程序 完整版 Vim 怎么装
RHEL、Rocky、AlmaLinux、CentOS vim-minimal 软件包提供的精简 Vim dnf install vim-enhanced(CentOS 7 用 yum),装好后命令是 vim
Debian、部分精简版 Ubuntu 镜像 vim-tiny,通过 alternatives 机制指向 vi apt install vim
Alpine、各类救援盘和嵌入式系统 BusyBox 内置的 vi,只有基本功能 Alpine 用 apk add vim

不确定手上这台机器用的是哪个,执行下面几条:

readlink -f "$(command -v vi)"         # vi 最终指向哪个程序
vi --version | head -n 2               # Vim 会显示 VIM - Vi IMproved 和版本号
vim --version | grep -o '[+-]syntax'   # +syntax 表示支持语法高亮

Debian 的 vim-tiny 有个常见困扰:在插入模式下按方向键,光标不动,反而多出一行字母 A、B、C 或 D。原因是 vim-tiny 默认以 vi 兼容模式运行,方向键发出的转义序列被拆成了几个普通按键:Esc 退出插入模式,O 在上方新开一行,最后的字母被当成文字输了进去。根本办法是装完整版 Vim;暂时装不了,就在 ~/.vimrc 里写上 set nocompatible 和 set backspace=indent,eol,start,退格键删不掉已有内容的问题也一起解决。

三种模式怎么切换:普通、插入、命令行

打开文件时 Vim 处于普通模式(Normal mode,很多中文资料叫“命令模式”)。这时键盘上的每个键都是命令:x 删除一个字符,dd 删除一行,u 撤销,字母并不会写进文件。要输入文字得先进入插入模式;要保存、退出、替换或跳到某一行,就按冒号进入命令行模式(也叫末行模式、底行模式),在屏幕最下面一行输入命令。

模式 怎么进入 屏幕上的标志 按键的作用 怎么回到普通模式
普通模式(命令模式) 打开文件即是;其他模式按 Esc 左下角没有模式提示 移动光标、删除、复制、粘贴、撤销 本身就是
插入模式 i 光标前、a 光标后、o 下方新开一行、A 行尾 左下角显示 -- INSERT --,中文环境为 -- 插入 -- 输入什么就写进什么 Esc
命令行模式(末行模式) 普通模式下按 :;按 / 或 ? 是查找 光标跳到最后一行,行首出现 : 或 / 输入 w、q、s/旧/新/ 等命令后回车执行 回车执行后自动返回,Esc 放弃
可视模式 v 按字符、V 按行、Ctrl+v 按列 -- VISUAL -- 移动光标扩大选区,再按 d、y、> 处理 Esc

可视模式不在“三种模式”的常见说法里,但改配置时经常用它选中一段再删除或缩进,值得一起记住。

几条让模式切换不出错的习惯:

  • 不知道自己在哪个模式,就连按两次 Esc。多按不会造成任何修改,最多响一声。
  • 在普通模式下操作前,先切到英文输入法。中文输入法打出的是全角冒号“:”,Vim 不认,看上去就像按了没反应。
  • 命令区分大小写。o 在下方开新行,O 在上方开新行;Caps Lock 开着时 j 变成 J(把两行合并),u 变成 U,结果完全不同。
  • 按了 Ctrl+S 后屏幕不动了,是终端的流量控制把输出暂停了,不是 Vim 卡死,按 Ctrl+Q 恢复。

实操一:用 Vim 修改 sshd_config

下面给 SSH 服务缩短登录等待时间、开启空闲保活,演示从打开到生效的完整过程。这两项改错了也不会把自己锁在外面,适合练手。以 root 身份操作,普通用户在命令前加 sudo。

第 1 步:备份并打开。 配置文件改坏了,有备份就能一条命令还原:

cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +%F).bak
vim +/LoginGraceTime /etc/ssh/sshd_config

+/关键词 让 Vim 打开文件后直接停在第一个匹配处。主流发行版的默认文件里,这一行是被注释掉的 #LoginGraceTime 2m。

第 2 步:按下表依次按键。

按键 作用 这一行变成
0 光标移到行首的 # #LoginGraceTime 2m
x 删除光标处的字符,即去掉注释符 LoginGraceTime 2m
w 光标跳到下一个词 2m 的开头 不变
cw,输入 30s,按 Esc 把从光标到词尾的 2m 改写成 30s LoginGraceTime 30s
/^#\?ClientAliveInterval 回车 查找以 ClientAliveInterval 或 #ClientAliveInterval 开头的行 光标停在 #ClientAliveInterval 0 行首的 # 上
x、w,再 cw,输入 60,按 Esc 去掉注释,把 0 改成 60 ClientAliveInterval 60
:wq 回车 保存并退出 —

cw 只改从光标到词尾的部分,所以先用 w 跳到词首再改;如果用 $ 跳到行尾的 m 上再按 cw,只有 m 被换掉,这一行会变成 LoginGraceTime 230s。查找时在关键词前加 ^#\?,表示“行首,可能有一个 #”,这样不会停在注释说明文字里提到这个词的地方。要新增一行配置,就在相关的那一行上按 o,在它下方新开一行输入;不要直接加到文件末尾,因为文件后部如果有生效的 Match 段,写在它后面的配置只对匹配的用户或地址生效。

第 3 步:检查语法、确认生效。

sshd -t                     # 没有任何输出就是语法正确
sshd -T | grep -Ei '^(logingracetime|clientaliveinterval) '
systemctl reload sshd       # Debian、Ubuntu 上服务名是 ssh
diff /etc/ssh/sshd_config.$(date +%F).bak /etc/ssh/sshd_config

sshd -T 打印的是 sshd 最终采用的值,时间统一换算成秒,这里应当看到 logingracetime 30 和 clientaliveinterval 60。如果值没变,多半是 /etc/ssh/sshd_config.d/ 目录里有文件先设置了同一个选项,sshd 对同一选项只取第一次读到的值,用 grep -r LoginGraceTime /etc/ssh/sshd_config.d/ 找出来一并修改。reload 不会断开现有连接,但改 SSH 配置时保持当前窗口不关,另开一个窗口测试能否登录,是值得养成的习惯。

实操二:改 nginx 配置,用上行号、块复制和批量替换

第二个例子换一个站点配置文件,把旧域名全部换成新域名,复制一个 location 块,再临时注释几行。

cp -a /etc/nginx/conf.d/shop.conf /root/shop.conf.bak
vim /etc/nginx/conf.d/shop.conf
  1. 显示行号。 输入 :set nu,后面用行号指定范围时以它为准,:set nonu 关闭。
  2. 批量换域名。 输入 :%s/old\.example\.com/shop.example.com/gc。% 表示全文,g 表示一行里出现多次也全部替换,c 表示每处先问你:按 y 替换、n 跳过、a 剩下的全部替换。点号在查找里匹配任意字符,所以旧域名里的 . 要写成 \.。
  3. 复制一个 location 块。 光标移到 location /api/ { 这一行,按 $ 跳到行尾的 {,再按 V%:V 开始按行选择,% 跳到与之配对的 },整个块就被选中了。按 y 复制,把光标移到要插入的位置,按 p 粘贴到下方,再把新块里的路径改掉。
  4. 临时注释第 40 到 45 行。 输入 :40,45s/^/# /,在每行行首加上 # ;恢复时执行 :40,45s/^# //。
  5. 调整缩进。 用 V 选中几行后按 > 右移一级、按 < 左移一级。
  6. 保存退出。 :wq。

然后检查并加载:

nginx -t && systemctl reload nginx

nginx -t 出错时会给出文件名和行号,例如 unexpected "}" in /etc/nginx/conf.d/shop.conf:42。用 vim +42 /etc/nginx/conf.d/shop.conf 打开,光标直接停在第 42 行。改到一半发现思路不对,:e! 丢弃所有未保存的修改、重新载入文件;已经保存的,就用开头备份的文件还原。

存不了、退不出:常见提示的意思

提示 意思 怎么办
E37: No write since last change (add ! to override) 文件改过还没保存,:q 被拒绝 要保存就 :wq,不要就 :q!
E45: 'readonly' option is set (add ! to override) 文件以只读方式打开,例如用了 view 或 vim -R 确认有写权限后用 :w! 强制写入
E212: Can't open file for writing 当前用户没有写权限,或文件所在目录不存在 见下文
E325: ATTENTION,并提到 swap file 这个文件有交换文件:可能有人正在编辑,也可能上次编辑时异常断开 见下文
E492: Not an editor command: Wq 命令没有识别,常见原因是大小写或全角符号 切换到英文输入法,用小写重新输入

E212:普通用户忘了加 sudo 就打开了 /etc 下的文件,改了半天存不进去。不必退出重改,输入 :w !sudo tee % > /dev/null,把当前内容交给 sudo tee 写回原文件(% 代表当前文件名)。写完 Vim 会提示文件已在外部被修改,按 L 重新载入,再 :q 退出。更稳妥的做法是先 :w /tmp/shop.conf.new 存到临时位置,退出后用 sudo 拷回去。

E325:Vim 编辑时会在同一目录下生成一个隐藏的交换文件(如 .shop.conf.swp),连接意外断开后靠它恢复内容。看到提示先确认有没有别人正在改:ps aux | grep '[v]im'。有人在改,按 Q 退出,等对方改完;提示里注明进程仍在运行时,Vim 也不会给出删除选项。没人在改,说明上次是异常退出:想找回没保存的内容就按 R 恢复,核对无误后保存,再手动删掉交换文件;确定不需要,就按 D 删除交换文件后正常编辑。

.vimrc:让服务器上的 Vim 顺手一些

Vim 启动时先读系统级配置(RHEL 系是 /etc/vimrc,Debian 系是 /etc/vim/vimrc),再读当前用户的 ~/.vimrc。个人习惯写进 ~/.vimrc,不要改系统文件:软件包升级时它可能被覆盖,也会影响这台机器上的其他人。下面这份配置适合运维改配置文件,需要完整版 Vim;用 vim-tiny 的机器只保留前面提到的两行即可。

set nocompatible                      " 关闭 vi 兼容模式
syntax on                             " 语法高亮
set number                            " 显示行号
set hlsearch incsearch                " 高亮查找结果,边输入边定位
set ignorecase smartcase              " 查找忽略大小写,输入了大写字母时才区分
set backspace=indent,eol,start        " 退格键可以删除任何内容
set expandtab tabstop=4 shiftwidth=4  " Tab 键输入 4 个空格
autocmd FileType yaml setlocal tabstop=2 shiftwidth=2
set fileencodings=utf-8,gb18030,latin1  " 打开文件时依次尝试的编码

expandtab 让 Tab 键输入空格,YAML 不允许用 Tab 缩进,这一项能避免很多格式错误;反过来,Makefile 必须用真正的 Tab,改它之前先执行 :set noexpandtab。fileencodings 里加上 gb18030,打开 Windows 上编辑过的中文文件时不容易乱码。

配置不必追求复杂。运维经常要在别人的机器、救援系统或刚装好的服务器上干活,那里只有默认的 vi,基本操作熟练比配置漂亮更有用。

机房场景:SSH 断了,也要能用 Vim 改回来

sshd_config 改坏、网卡配置写错,最直接的后果是 SSH 连不上,这时只能从本机控制台登录去改。服务器有 BMC 的话,通过带外管理打开的控制台不依赖操作系统的网络,登录后同样用 Vim 把配置改回来,备份文件在这时就派上了用场。Toplink DCIM 的 IPMI 远程管理在浏览器里打开走 BMC 通道的 VNC 控制台,可以把剪贴板内容粘贴进去,也能发送 Ctrl+Alt+Del 这类组合键;粘贴大段配置前在 Vim 里先执行 :set paste,免得自动缩进把格式打乱。系统已经进不去时,租用服务器的客户可以在客户自助端启动救援模式,挂载硬盘后用同样的方法修改,硬盘上的数据不受影响。

常见问题

vim 和 nano 用哪个?

nano 把快捷键列在屏幕底部,上手更快;但救援系统、精简容器和各种嵌入式系统里往往只有 vi。日常用哪个都行,但 vi 的基本操作一定要会。crontab -e 打开哪个编辑器由 VISUAL 或 EDITOR 环境变量决定,在 ~/.bashrc 里加一行 export EDITOR=vim 即可;Debian 系也可以用 update-alternatives --config editor 设置默认编辑器。

Neovim 和 Vim 是什么关系?

Neovim 是 2014 年从 Vim 分出来的项目,按键和绝大多数命令与 Vim 相同,配置可以用 Lua,也兼容大部分 Vim script。服务器上默认装的一般还是 Vim,会用 Vim 就能直接上手 Neovim。

有没有能边学边练的教程?

完整版 Vim 自带 vimtutor 命令,它会打开一份教程的临时副本,按提示一步步练习移动、删除、插入和保存,大约 30 分钟走完,练习时怎么改都不会影响系统里的任何文件。

想看看在你的机房里怎么用?

从一次产品演示开始,梳理你的业务链路。

查看价格
服务热线 400-112-2951

让我们聊聊你的 IDC 业务

扫码添加企业微信,预约产品演示或申请试用。

Toplink 企业微信二维码

长按保存或使用企业微信 / 微信扫描

也可致电
400-112-2951
Telegram
@TopLink88