Stories

Detail Return Return

Vim 進階教程 - Stories Detail

文本替換 (:s)

這是 Vim 中最強大和最常用的進階功能之一。

基本語法: :[range]s/old/new/[flags]

  • [range]: 指定替換操作的範圍。省略時默認為當前行。

    • %:整個文件 (例如 :%s/old/new/)
    • 5,10:第 5 行到第 10 行 (例如 :5,10s/old/new/)
    • .,$:從當前行到文件末尾 (例如 :.,$s/old/new/)
    • .+1,$-1:從當前行下一行到文件倒數第二行
    • /pattern1/,/pattern2/:從匹配 pattern1 的行到匹配 pattern2 的行
    • '<,'>:當前選中的可視區域(在可視模式下按 : 後自動填充)
  • s: substitute (替換) 命令。
  • old: 要被替換的文本(模式)。支持正則表達式! (這是它強大的核心)
  • new: 替換成的新文本。
  • [flags]: 控制替換行為的標誌(可選,可組合使用)。

    • g (global): 對一行內的所有匹配項進行替換(默認只替換一行中的第一個匹配項)。非常重要!
    • c (confirm): 每次替換前要求確認。按 y 替換,n 跳過,a 替換所有,q 退出替換。
    • i (ignore case): 忽略大小寫進行匹配。
    • I (no ignore case): 區分大小寫進行匹配(默認行為)。
    • e (no errors): 如果 old 沒有匹配項,不報錯(抑制錯誤信息)。

常見示例:

  • 替換當前行第一個 foobar:s/foo/bar/
  • 替換當前行所有 foobar:s/foo/bar/g
  • 替換整個文件中所有 foobar (全局替換): :%s/foo/bar/g
  • 替換第 10 行到第 20 行所有 foobar:10,20s/foo/bar/g
  • 替換整個文件中所有 foobar,但每次替換前確認: :%s/foo/bar/gc
  • 將文件中所有 colorcolour 替換為 hue (忽略大小寫): :%s/colou\?r/hue/gi (這裏 \? 表示前面的 u 可有可無,i 忽略大小寫)
  • 刪除所有行尾的空白字符: :%s/\s\+$//g (\s\+ 匹配一個或多個空白字符,$ 匹配行尾)
  • 刪除所有行首的空白字符: :%s/^\s\+//g (^ 匹配行首)
  • "name" 替換為 'name':%s/"$$[^"]*$$"/'\1'/g (使用捕獲組 $$...$$ 和反向引用 \1)
  • 在變量名後添加 _v2(捕獲組 \1)::%s/\<\(\w\+\)\>/\1_v2/g

重要提示:

  • 正則表達式是核心: 要充分利用 :s,必須學習基礎的正則表達式 (Vim 使用自己的變種,但基礎與其他類似)。
  • 分隔符 / 可替換: 如果 oldnew 中包含 /,可以用其他字符作為分隔符,如 :s#old#new#g:s@old@new@g
  • 先確認 (c 標誌): 對於全局替換 (:%s/...),尤其是在生產代碼中,強烈建議使用 c 標誌先檢查確認。
  • 查看匹配: 在輸入 :s/old 後,按 Ctrl-R Ctrl-W (在命令模式下) 可以將光標下的單詞插入到命令中。在替換前使用 /old 搜索一下,用 :nohl 取消高亮,可以直觀看到哪些地方會被匹配。

批量操作/多文件操作

多行編輯(可視化塊模式)

結合 Ctrl + v(垂直選中)實現批量添加 / 刪除前綴 / 後綴:

  • 批量給多行添加前綴(如註釋符號 //):

    • Ctrl + v 進入垂直選擇模式
    • 移動光標選中需要操作的行(如向下按 j 選 5 行)
    • I(大寫 I,進入插入模式),輸入前綴(如 //
    • ESC,所有選中行都會添加前綴
  • 批量刪除多行前綴:

    • Ctrl + v 選中需要刪除的前綴列(如前 2 個字符)
    • d 直接刪除選中的列

argdo / bufdo / windo / tabdo:

  • 這些命令允許在多個參數列表文件(argdo)、緩衝區(bufdo)、窗口(windo)、標籤頁(tabdo) 上執行相同的 Ex 命令。
  • 示例:

    • 打開多個文件: vim *.txt
    • 在所有打開的 .txt 文件中替換 oldnew:argdo %s/old/new/ge | update

      • %s/old/new/ge:在每個文件內執行全局替換 (g),忽略錯誤 (e 防止沒有匹配的文件報錯退出)。
      • | update:管道符 | 連接命令,update 僅在文件被修改過時才保存。
    • 在所有打開的緩衝區中執行替換並保存: :bufdo %s/old/new/ge | w
  • 注意:argdo 操作的是 :args 列表中的文件,bufdo 操作的是所有加載到緩衝區的文件。

:vimgrep / :grep:

  • 在整個項目文件中搜索包含特定模式的行。
  • :vimgrep /pattern/[j][g] file(s)

    • /pattern/:搜索模式(支持 Vim 強大的正則)。
    • [j]:不跳轉到第一個匹配項(靜默搜索)。
    • [g]:每行只列出一次匹配(默認列出每行的所有匹配)。
    • file(s):文件模式,如 **/*.py 遞歸搜索所有 .py 文件。
    • 示例: :vimgrep /TODO/ **/*.py (在所有 .py 文件中搜索 "TODO")
  • 搜索結果會填充到 quickfix 列表 (:copen 打開列表,:cclose 關閉,:cn 下一個,:cp 上一個)。
  • 結合 :cdo / :cfdo

    • :cdo command:對 quickfix 列表中的每一行執行命令 (光標會移動到對應行)。
    • :cfdo command:對 quickfix 列表中的每一個文件執行命令 (光標會移動到對應文件)。
    • 強大示例: 在所有包含 "TODO".py 文件中,將 "TODO" 替換為 "FIXME"

      :vimgrep /TODO/ **/*.py

      • :cfdo %s/TODO/FIXME/ge | update
      • 對每個匹配文件 (:cfdo) 執行全局替換 (%s/.../g),忽略錯誤 (e),修改才保存 (update)。

宏錄製 (q):

  • 錄製: q + <register> (例如 qa) 開始錄製到寄存器 a -> 執行你的操作序列 -> q 停止錄製。
  • 播放: @ + <register> (例如 @a) 播放寄存器 a 中的宏。@@ 重複播放上一次播放的宏。
  • 批量播放: 結合行號或可視選擇。

    • :10,20 normal @a:對第 10 行到第 20 行的每一行,在普通模式下執行寄存器 a 中的宏。
    • 在可視模式下選中多行,然後按 :,會自動填充為 :'<,'>,然後輸入 normal @a
  • 示例: 給一組連續的行添加註釋 (// ):

    • 將光標移動到第一行的行首。
    • qa 開始錄製到 a
    • I// <Esc>:進入插入模式,輸入 // ,退出插入模式。
    • j:移動到下一行。
    • q:停止錄製。
    • @a 對當前行執行宏(添加註釋並下移一行)。
    • 5@a 重複執行 5 次宏(給接下來的 5 行添加註釋)。或者用 jVG 選中剩餘行,然後 :'<,'>normal @a

其他高級技巧

重複操作(.命令)

. 可以重複上一次的編輯操作,是 Vim 最被低估的技巧之一:

  • 例 1:刪除一行後,按 . 會重複刪除下一行
  • 例 2:在某行末尾添加 ;,按 .會在其他行末尾重複添加

快速跳轉與定位

  • 按內容跳轉:

    • *:向下跳轉到當前單詞的下一個匹配
    • #:向上跳轉到當前單詞的上一個匹配
  • 跳轉到上次編輯位置:

    • ''(兩個單引號):跳回上一次跳轉前的位置
    • .(點符號):跳轉到上次編輯的位置

global 命令 (:g):

  • 對匹配特定模式的行執行命令。
  • 語法: :[range]g/pattern/command
  • 示例:

    • 刪除所有空行: :g/^$/d (匹配行首 ^ 緊接着行尾 $ 的行,即空行,執行 d 刪除)。
    • 刪除所有包含 DEBUG 的行: :g/DEBUG/d
    • 將所有包含 TODO 的行復制到文件末尾: :g/TODO/t$ (tcopy 的縮寫,$ 表示文件末尾)。
    • 在包含 function 的行前面添加註釋: :g/function/normal O// TODO: Implement

全局反向操作(:vglobal)

  • :v/^$/d:刪除所有非空行

寄存器 (") 的高級使用:

寄存器 含義
" 默認寄存器,存放最近一次的刪除或複製
0 存放最近一次的複製(y 命令)
1–9 最近 9 次刪除操作 (滾動存放)
a–z 用户自定義寄存器,可用 "ayy 複製到 a
/: 存放最近一次的搜索模式
  • 指定寄存器: 在操作命令前加上 "<register>

    • "ayy:複製當前行到寄存器 a
    • "bdd:刪除當前行到寄存器 b (剪切)。
    • "ap:粘貼寄存器 a 的內容。
  • 查看寄存器內容: :reg:reg <register> (如 :reg a)。
  • 系統剪貼板 ("+ / "*): 設置了 clipboard=unnamed,通常 "+"* 都指向系統剪貼板。顯式使用:

    • "+yy:複製當前行到系統剪貼板。
    • "+p:粘貼系統剪貼板內容到 Vim
  • 只讀寄存器:

    • "%:當前文件名。
    • ".:上次插入的文本。
    • "::上次執行的命令。
    • "/:上次搜索的模式。

摺疊代碼

  • zc:摺疊當前代碼塊(如函數、循環)
  • zo:展開當前摺疊塊
  • zR:展開所有摺疊
  • zM:摺疊所有代碼塊

(需先設置摺疊方式:set foldmethod=indent 按縮進摺疊,或 set foldmethod=syntax 按語法摺疊)

顯示不可見字符

查看空格、製表符、換行符等:

:set list  " 顯示不可見字符($表示換行,^I表示製表符)
:set nolist  " 關閉顯示

標記 (Marks):

  • 快速跳轉到文件中的特定位置。
  • 設置標記: m + <letter> (例如 ma 設置標記 a)。
  • 跳轉到標記:
` + <letter>

(反引號,例如 `a 精確跳轉到標記 a 的行和列) 或

' + <letter>

(單引號,例如 'a 跳轉到標記 a 所在行的行首)。

  • 查看標記: :marks
  • 特殊標記:

    • ``:跳回上次跳轉前的位置。
    • '.:上次修改的行。
    • '^:上次插入模式退出的位置。

會話管理 (Sessions)

  • 保存會話(打開的文件、窗口布局等):
:mksession ~/session.vim
  • 恢復會話:
vim -S ~/session.vim

外部命令與管道

  • Vim 中執行 shell 命令並將結果導入緩衝區:
:r !ls -l
  • 對選中區域執行外部命令:
:'<,'>!sort

將選區內內容按 sort 排序。

自動命令 (autocmd):

  • 在特定事件發生時自動執行命令,用於高度定製 Vim 行為(如文件類型檢測、保存時自動格式化等)。這屬於更高級的 .vimrc 配置。
  • 基本示例 (在 .vimrc 中):
" 當打開或新建 .py 文件時設置縮進
autocmd BufNewFile,BufRead *.py setlocal tabstop=4 shiftwidth=4 expandtab
" 保存 .py 文件前自動刪除行尾空白
autocmd BufWritePre *.py :%s/\s\+$//e

窗口和標籤頁管理:

  • 分割窗口:

    • :split / :sp [filename]:水平分割當前窗口(或打開文件)。
    • :vsplit / :vsp [filename]:垂直分割當前窗口(或打開文件)。
    • Ctrl-w s:水平分割。
    • Ctrl-w v:垂直分割。
    • Ctrl + w + =:讓所有分屏高度 / 寬度相等
  • 窗口間跳轉: Ctrl-w h/j/k/l / Ctrl-w w (循環)。
  • 關閉窗口: :close / Ctrl-w c
  • 調整窗口大小: Ctrl-w + / Ctrl-w - (高度), Ctrl-w > / Ctrl-w < (寬度)。
  • 標籤頁:

    • :tabnew [filename]:在新標籤頁打開文件。
    • :tabclose:關閉當前標籤頁。
    • :tabnext / gt:下一個標籤頁。
    • :tabprevious / gT:上一個標籤頁。
    • :tabm [n]:移動當前標籤頁到位置 n (從 0 開始計數)。

命令行窗口 (q:):

  • 普通模式下按 q: 打開命令行窗口。這裏顯示命令歷史,可以像編輯普通文本一樣瀏覽、修改歷史命令,然後按回車執行選中的命令。非常方便修改複雜命令(如帶複雜正則的 :s 命令)。
  • 表達式寄存器 (=):

    • 在插入模式下按 Ctrl-r =,可以輸入一個 Vim 表達式(如 2+2@a),計算結果會插入到文本中。高級用法可以結合函數。
  • normal 命令 (:normal):

    • 在命令行模式下執行普通模式的命令序列。
    • 示例:

      • 在當前行執行宏 a:normal @a
      • 在選中的行(可視模式後)刪除行首空白: :'<,'>normal ^dW (先跳到行首非空字符 ^,然後刪除一個單詞 dW,這裏空白被當作一個單詞)。
  • 符號自動補全 (Ctrl-x 系列):

    • 在插入模式下:

      • Ctrl-x Ctrl-l:整行補全。
      • Ctrl-x Ctrl-f:文件名補全。
      • Ctrl-x Ctrl-o:全能 (Omni) 補全(需要文件類型支持,如編程語言)。
      • Ctrl-n / Ctrl-p:使用當前緩衝區中的單詞補全。
  • 自動縮進 (=):

    • 在可視模式下選中代碼塊,按 = 會自動縮進(根據文件類型和你的 indent 設置)。
    • gg=G:對整個文件進行自動縮進 (gg 到文件頭,= 縮進操作,G 到文件尾)。

高級配置技巧(需修改.vimrc)

高效搜索

  • set incsearch:輸入搜索詞時實時高亮匹配
  • set hlsearch:高亮所有搜索結果,用 :nohl 臨時關閉高亮

文件管理

  • set autochdir:自動切換工作目錄到當前文件位置
  • set wildmenu:增強文件名補全(按 Tab 循環選擇)

備份與撤銷

  • set undodir=\~/.vim/undo:持久化撤銷歷史(支持關閉文件後仍可撤銷)

代碼格式化

  • filetype indent on:根據文件類型自動縮進
  • set tabstop=4:設置 Tab 為4空格

插件推薦(進階工具)

  • 多文件搜索:
    fzf.vim(模糊搜索文件/內容)
  • 批量註釋:
    vim-commentarygc 快速註釋)
  • 環繞編輯:
    vim-surroundcs"' 替換雙引號為單引號)
  • 自動補全:
    coc.nvimLSP 支持)
  • 項目目錄樹瀏覽、文件管理。
    nerdtree
  • 實時顯示 Git diff(新增、修改、刪除行)

    vim-gitgutter / signify

其他示例

將項目中的 user_id 改為 user_id_new:

  • 精確全文替換:
:%s/\<user_id\>/user_id_new/gc
  • 如果涉及多個文件:
:argdo %s/\<user_id\>/user_id_new/ge | update

關鍵點:

  • \<\> 匹配單詞邊界(避免匹配 _user_id_old
  • /e 屏蔽未匹配時的報錯
  • | update 只保存修改過的文件
user avatar dhan Avatar
Favorites 1 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.