Vim 編輯器是什麼:三種模式與修改配置檔案實操
Vim 編輯器是 vi 的增強版,在沒有圖形介面的 Linux 伺服器上用來檢視和修改配置檔案。它靠模式工作:開啟檔案時處於普通模式,按 i 進入插入模式輸入文字,按 Esc 回到普通模式,再輸入 :wq 儲存退出。記住這個迴圈,大多數配置就能改完。
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
- 顯示行號。 輸入
:set nu,後面用行號指定範圍時以它為準,:set nonu關閉。 - 批次換域名。 輸入
:%s/old\.example\.com/shop.example.com/gc。%表示全文,g表示一行裡出現多次也全部替換,c表示每處先問你:按y替換、n跳過、a剩下的全部替換。點號在查詢裡匹配任意字元,所以舊域名裡的.要寫成\.。 - 複製一個 location 塊。 游標移到
location /api/ {這一行,按$跳到行尾的{,再按V%:V開始按行選擇,%跳到與之配對的},整個塊就被選中了。按y複製,把游標移到要插入的位置,按p貼上到下方,再把新塊裡的路徑改掉。 - 臨時註釋第 40 到 45 行。 輸入
:40,45s/^/# /,在每行行首加上#;恢復時執行:40,45s/^# //。 - 調整縮排。 用
V選中幾行後按>右移一級、按<左移一級。 - 儲存退出。
: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 分鐘走完,練習時怎麼改都不會影響系統裡的任何檔案。