# `vi` —— 終端中的編輯器 ## 目標 * `vi` 簡介* 打開和新建文件* 三種工作模式* 常用命令* 分屏命令* 常用命令速查圖 ## 01. `vi` 簡介 ### 1.1 學習 `vi` 的目的 * 在工作中,要對 **伺服器** 上的文件進行 **簡單** 的修改,可以使用 `s ...
# `vi` —— 終端中的編輯器
## 目標
* `vi` 簡介
* 打開和新建文件
* 三種工作模式
* 常用命令
* 分屏命令
* 常用命令速查圖
## 01. `vi` 簡介
### 1.1 學習 `vi` 的目的
* 在工作中,要對 **伺服器** 上的文件進行 **簡單** 的修改,可以使用 `ssh` 遠程登錄到伺服器上,並且使用 `vi` 進行快速的編輯即可
* 常見需要修改的文件包括:
* **源程式**
* **配置文件**,例如 `ssh` 的配置文件 `~/.ssh/config`
> * 在沒有圖形界面的環境下,要編輯文件,`vi` 是最佳選擇!
> * 每一個要使用 Linux 的程式員,都應該或多或少的學習一些 `vi` 的常用命令
### 1.2 vi 和 vim
* 在很多 `Linux` 發行版中,直接把 `vi` 做成 `vim` 的軟連接
#### vi
* `vi` 是 `Visual interface` 的簡稱,是 `Linux` 中 **最經典** 的文本編輯器
* `vi` 的核心設計思想 —— **讓程式員的手指始終保持在鍵盤的核心區域,就能完成所有的編輯操作**
* `vi` 的特點:
* **沒有圖形界面** 的 **功能強大** 的編輯器
* 只能是編輯 **文本內容**,不能對字體、段落進行排版
* **不支持滑鼠操作**
* **沒有菜單**
* **只有命令**
* `vi` 編輯器在 **系統管理**、**伺服器管理** 編輯文件時,**其功能永遠不是圖形界面的編輯器能比擬的**
#### `vim`
**vim = vi improved**
* `vim` 是從 `vi` 發展出來的一個文本編輯器,支持 **代碼補全**、**編譯** 及 **錯誤跳轉** 等方便編程的功能特別豐富,在程式員中被廣泛使用,被稱為 **編輯器之神**
#### 查詢軟連接命令(知道)
* 在很多 `Linux` 發行版中直接把 `vi` 做成 `vim` 的軟連接
```bash
# 查找 vi 的運行文件
$ which vi
$ ls -l /usr/bin/vi
$ ls -l /etc/alternatives/vi
$ ls -l /usr/bin/vim.basic
# 查找 vim 的運行文件
$ which vim
$ ls -l /usr/bin/vim
$ ls -l /etc/alternatives/vim
$ ls -l /usr/bin/vim.basic
```
## 02. 打開和新建文件
* 在終端中輸入 `vi` **在後面跟上文件名** 即可
```bash
$ vi 文件名
```
* 如果文件已經存在,會直接打開該文件
* 如果文件不存在,會新建一個文件
### 2.1 打開文件並且定位行
* 在日常工作中,有可能會遇到 **打開一個文件,並定位到指定行** 的情況
* 例如:在開發時,**知道某一行代碼有錯誤**,可以 **快速定位** 到出錯代碼的位置
* 這個時候,可以使用以下命令打開文件
```bash
$ vi 文件名 +行數
```
> 提示:如果只帶上 `+` 而不指定行號,會直接定位到文件末尾
### 2.2 異常處理
* 如果 `vi` 異常退出,在磁碟上可能會保存有 **交換文件**
* 下次再使用 `vi` 編輯該文件時,會看到以下屏幕信息,按下字母 `d` 可以 **刪除交換文件** 即可
> 提示:按下鍵盤時,註意關閉輸入法
## 03. 三種工作模式
* `vi` 有三種基本工作模式:
1. **命令模式**
* **打開文件首先進入命令模式**,是使用 `vi` 的 **入口**
* 通過 **命令** 對文件進行常規的編輯操作,例如:**定位**、**翻頁**、**複製**、**粘貼**、**刪除**……
* 在其他圖形編輯器下,通過 **快捷鍵** 或者 **滑鼠** 實現的操作,都在 **命令模式** 下實現
2. **末行模式** —— 執行 **保存**、**退出** 等操作
* 要退出 `vi` 返回到控制台,需要在末行模式下輸入命令
* **末行模式** 是 `vi` 的 **出口**
3. **編輯模式** —— 正常的編輯文字
> 提示:在 `Touch Bar` 的 Mac 電腦上 ,按 `ESC` 不方便,可以使用 `CTRL + [` 替代
### 末行模式命令
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| w | write | 保存 |
| q | quit | 退出,如果沒有保存,不允許退出 |
| q! | quit | 強行退出,不保存退出 |
| wq | write & quit | 保存並退出 |
| x | | 保存並退出 |
## 04. 常用命令
### 命令線路圖
0. 重覆次數
* 在命令模式下,**先輸入一個數字**,**再跟上一個命令**,可以讓該命令 **重覆執行指定次數**
1. 移動和選擇(**多練**)
* `vi` 之所以快,關鍵在於 **能夠快速定位到要編輯的代碼行**
* **移動命令** 能夠 和 **編輯操作** 命令 **組合使用**
2. 編輯操作
* **刪除**、**複製**、**粘貼**、**替換**、**縮排**
3. 撤銷和重覆
4. 查找替換
5. 編輯
#### 學習提示
1. `vi` 的命令較多,**不要期望一下子全部記住**,個別命令忘記了,只是會影響編輯速度而已
2. 在使用 `vi` 命令時,註意 **關閉中文輸入法**
### 4.1 移動(基本)
* 要熟練使用 `vi`,首先應該學會怎麼在 **命令模式** 下樣快速移動游標
* **編輯操作命令**,能夠和 **移動命令** 結合在一起使用
#### 1) 上、下、左、右
| 命令 | 功能 | 手指 |
| :---: | --- | :---: |
| h | 向左 | 食指 |
| j | 向下 | 食指 |
| k | 向上 | 中指 |
| l | 向右 | 無名指 |
#### 2) 行內移動
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| w | word | 向後移動一個單詞 |
| b | back | 向前移動一個單詞 |
| 0 | | 行首 |
| ^ | | 行首,第一個不是空白字元的位置 |
| $ | | 行尾 |
#### 3) 行數移動
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| gg | go | 文件頂部 |
| G | go | 文件末尾 |
| 數字gg | go | 移動到 數字 對應行數 |
| 數字G | go | 移動到 數字 對應行數 |
| :數字 | | 移動到 數字 對應行數 |
#### 4) 屏幕移動
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| Ctrl + b | back | 向上翻頁 |
| Ctrl + f | forward | 向下翻頁 |
| H | Head | 屏幕頂部 |
| M | Middle | 屏幕中間 |
| L | Low | 屏幕底部 |
### 4.2 移動(程式)
#### 1) 段落移動
* `vi` 中使用 空行 來區分段落
* 在程式開發時,通常 **一段功能相關的代碼會寫在一起** —— 之間沒有空行
| 命令 | 功能 |
| :---: | --- |
| { | 上一段 |
| } | 下一段 |
#### 2) 括弧切換
* 在程式世界中,`()`、`[]`、`{}` 使用頻率很高,而且 **都是成對出現的**
| 命令 | 功能 |
| :---: | --- |
| % | 括弧匹配及切換 |
#### 3) 標記
* 在開發時,某一塊代碼可能**需要稍後處理**,例如:編輯、查看
* 此時先使用 `m` 增加一個標記,這樣可以 **在需要時快速地跳轉回來** 或者 **執行其他編輯操作**
* **標記名稱** 可以是 `a~z` 或者 `A~Z` 之間的任意 **一個** 字母
* 添加了標記的 **行如果被刪除**,**標記同時被刪除**
* 如果 **在其他行添加了相同名稱的標記**,**之前添加的標記也會被替換掉**
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| mx | mark | 添加標記 x,x 是 a~z 或者 A~Z 之間的任意一個字母 |
| 'x | | 直接定位到標記 x 所在位置 |
### 4.3 選中文本(可視模式)
* 學習 `複製` 命令前,應該先學會 **怎麼樣選中 要複製的代碼**
* 在 `vi` 中要選擇文本,需要先使用 `Visual` 命令切換到 **可視模式**
* `vi` 中提供了 **三種** 可視模式,可以方便程式員選擇 **選中文本的方式**
* 按 `ESC` 可以放棄選中,返回到 **命令模式**
| 命令 | 模式 | 功能 |
| :---: | --- | --- |
| v | 可視模式 | 從游標位置開始按照正常模式選擇文本 |
| V | 可視行模式 | 選中游標經過的完整行 |
| Ctrl + v | 可視塊模式 | 垂直方向選中文本 |
* **可視模式**下,可以和 **移動命令** 連用,例如:`ggVG` 能夠選中所有內容
### 4.4 撤銷和恢復撤銷
* 在學習編輯命令之前,先要知道怎樣撤銷之前一次 **錯誤的** 編輯動作!
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| u | undo | 撤銷上次命令 |
| CTRL + r | redo | 恢復撤銷的命令 |
### 4.5 刪除文本
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| x | cut | 刪除游標所在字元,或者選中文字 |
| d(移動命令) | delete | 刪除移動命令對應的內容 |
| dd | delete | 刪除游標所在行,可以 ndd 複製多行 |
| D | delete | 刪除至行尾 |
> 提示:如果使用 **可視模式** 已經選中了一段文本,那麼無論使用 `d` 還是 `x`,都可以刪除選中文本
* 刪除命令可以和 **移動命令** 連用,以下是常見的組合命令:
```
* dw # 從游標位置刪除到單詞末尾
* d0 # 從游標位置刪除到一行的起始位置
* d} # 從游標位置刪除到段落結尾
* ndd # 從游標位置向下連續刪除 n 行
* d代碼行G # 從游標所在行 刪除到 指定代碼行 之間的所有代碼
* d'a # 從游標所在行 刪除到 標記a 之間的所有代碼
```
### 4.6 複製、粘貼
* `vi` 中提供有一個 **被覆制文本的緩衝區**
* **複製** 命令會將選中的文字保存在緩衝區
* **刪除** 命令刪除的文字會被保存在緩衝區
* 在需要的位置,使用 **粘貼** 命令可以將緩衝區的文字插入到游標所在位置
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| y(移動命令) | copy | 複製 |
| yy | copy | 複製一行,可以 nyy 複製多行 |
| p | paste | 粘貼 |
**提示**
* 命令 `d`、`x` 類似於圖形界面的 **剪切操作** —— `CTRL + X`
* 命令 `y` 類似於圖形界面的 **複製操作** —— `CTRL + C`
* 命令 `p` 類似於圖形界面的 **粘貼操作** —— `CTRL + V`
* `vi` 中的 **文本緩衝區同樣只有一個**,如果後續做過 **複製、剪切** 操作,之前緩衝區中的內容會被替換
**註意**
* `vi` 中的 **文本緩衝區** 和系統的 **剪貼板** 不是同一個
* 所以在其他軟體中使用 `CTRL + C` 複製的內容,不能在 `vi` 中通過 `P` 命令粘貼
* 可以在 **編輯模式** 下使用 **滑鼠右鍵粘貼**
### 4.7 替換
| 命令 | 英文 | 功能 | 工作模式 |
| :---: | :---: | --- | --- |
| r | replace | 替換當前字元 | 命令模式 |
| R | replace | 替換當前行游標後的字元 | 替換模式 |
* `R` 命令可以進入 **替換模式**,替換完成後,按下 `ESC` 可以回到 **命令模式**
* **替換命令** 的作用就是不用進入 **編輯模式**,對文件進行 **輕量級的修改**
### 4.8 縮排和重覆執行
| 命令 | 功能 |
| :---: | --- |
| >> | 向右增加縮進 |
| << | 向左減少縮進 |
| . | 重覆上次命令 |
* **縮排命令** 在開發程式時,**統一增加代碼的縮進** 比較有用!
* 一次性 **在選中代碼前增加 4 個空格**,就叫做 **增加縮進**
* 一次性 **在選中代碼前刪除 4 個空格**,就叫做 **減少縮進**
* 在 **可視模式** 下,縮排命令只需要使用 **一個** `>` 或者 `<`
> 在程式中,**縮進** 通常用來表示代碼的歸屬關係
>
> * 前面空格越少,代碼的級別越高
> * 前面空格越多,代碼的級別越低
### 4.9 查找
#### 常規查找
| 命令 | 功能 |
| :---: | --- |
| /str | 查找 str |
* 查找到指定內容之後,使用 `Next` 查找下一個出現的位置:
* `n`: 查找下一個
* `N`: 查找上一個
* 如果不想看到高亮顯示,可以隨便查找一個文件中不存在的內容即可
#### 單詞快速匹配
| 命令 | 功能 |
| :---: | --- |
| * | 向後查找當前游標所在單詞 |
| # | 向前查找當前游標所在單詞 |
* 在開發中,通過單詞快速匹配,可以快速看到這個單詞在其他什麼位置使用過
### 4.10 查找並替換
* 在 `vi` 中查找和替換命令需要在 **末行模式** 下執行
* 記憶命令格式:
```
:%s///g
```
#### 1) 全局替換
* **一次性**替換文件中的 **所有出現的舊文本**
* 命令格式如下:
```
:%s/舊文本/新文本/g
```
#### 2) 可視區域替換
* **先選中** 要替換文字的 **範圍**
* 命令格式如下:
```
:s/舊文本/新文本/g
```
#### 3) 確認替換
* 如果把末尾的 `g` 改成 `gc` 在替換的時候,會有提示!**推薦使用!**
```
:%s/舊文本/新文本/gc
```
1. `y` - `yes` 替換
2. `n` - `no` 不替換
3. `a` - `all` 替換所有
4. `q` - `quit` 退出替換
5. `l` - `last` 最後一個,並把游標移動到行首
6. `^E` 向下滾屏
7. `^Y` 向上滾屏
### 4.11 插入命令
* 在 `vi` 中除了常用的 `i` 進入 **編輯模式** 外,還提供了以下命令同樣可以進入編輯模式:
| 命令 | 英文 | 功能 | 常用 |
| :---: | :---: | --- | :---: |
| i | insert | 在當前字元前插入文本 | 常用 |
| I | insert | 在行首插入文本 | 較常用 |
| a | append | 在當前字元後添加文本 | |
| A | append | 在行末添加文本 | 較常用 |
| o | | 在當前行後面插入一空行 | 常用 |
| O | | 在當前行前面插入一空行 | 常用 |
#### 演練 1 —— 編輯命令和數字連用
* 在開發中,可能會遇到連續輸入 `N` 個同樣的字元
> 在 `Python` 中有簡單的方法,但是其他語言中通常需要自己輸入
* 例如:`**********` 連續 10 個星號
要實現這個效果可以在 **命令模式** 下
1. 輸入 `10`,表示要重覆 10 次
2. 輸入 `i` 進入 **編輯模式**
3. 輸入 `*` 也就是重覆的文字
4. 按下 `ESC` 返回到 **命令模式**,返回之後 `vi` 就會把第 `2、3` 兩步的操作重覆 `10` 次
> 提示:正常開發時,在 **進入編輯模式之前,不要按數字**
#### 演練 2 —— 利用 可視塊 給多行代碼增加註釋
* 在開發中,可能會遇到一次性給多行代碼 **增加註釋** 的情況
> 在 `Python` 中,要給代碼增加註釋,可以在代碼前增加一個 `# `
要實現這個效果可以在 **命令模式** 下
1. 移動到要添加註釋的 **第 1 行代碼**,按 `^` 來到行首
2. 按 `CTRL + v` 進入 **可視塊** 模式
3. 使用 `j` 向下連續選中要添加的代碼行
4. 輸入 `I` 進入 **編輯模式**,併在 **行首插入**,註意:一定要使用 **I**
5. 輸入 `# ` 也就是註釋符號
6. 按下 `ESC` 返回到 **命令模式**,返回之後 `vi` 會在之前選中的每一行代碼 **前** 插入 `# `
## 05. 分屏命令
* 屬於 `vi` 的高級命令 —— 可以 **同時編輯和查看多個文件**
### 5.1 末行命令擴展
**末行命令** 主要是針對文件進行操作的:**保存**、**退出**、**保存&退出**、**搜索&替換**、**另存**、**新建**、**瀏覽文件**
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| :e . | edit | 會打開內置的文件瀏覽器,瀏覽要當前目錄下的文件 |
| :n 文件名 | new | 新建文件 |
| :w 文件名 | write | 另存為,但是仍然編輯當前文件,並不會切換文件 |
> 提示:切換文件之前,必須保證當前這個文件已經被保存!
* 已經學習過的 **末行命令**:
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| :w | write | 保存 |
| :q | quit | 退出,如果沒有保存,不允許退出 |
| :q! | quit | 強行退出,不保存退出 |
| :wq | write & quit | 保存並退出 |
| :x | | 保存並退出 |
| :%s///gc | | 確認搜索並替換 |
> 在實際開發中,可以使用 `w` 命令 **階段性的備份代碼**
### 5.2 分屏命令
* 使用 **分屏命令**,可以 **同時編輯和查看多個文件**
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| :sp [文件名] | split | 橫向增加分屏 |
| :vsp [文件名] | vertical split | 縱向增加分屏 |
#### 1) 切換分屏視窗
> 分屏視窗都是基於 `CTRL + W` 這個快捷鍵的,`w` 對應的英文單詞是 `window`
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| w | window | 切換到下一個視窗 |
| r | reverse | 互換視窗 |
| c | close | 關閉當前視窗,但是不能關閉最後一個視窗 |
| q | quit | 退出當前視窗,如果是最後一個視窗,則關閉 vi |
| o | other | 關閉其他視窗 |
#### 2) 調整視窗大小
> 分屏視窗都是基於 `CTRL + W` 這個快捷鍵的,`w` 對應的英文單詞是 `window`
| 命令 | 英文 | 功能 |
| :---: | :---: | --- |
| + | | 增加視窗高度 |
| - | | 減少視窗高度 |
| > | | 增加視窗寬度 |
| < | | 減少視窗寬度 |
| = | | 等分視窗大小 |
> 調整視窗寬高的命令可以和數字連用,例如:`5 CTRL + W +` 連續 5 次增加高度
## 06. 常用命令速查圖
### vimrc
* `vimrc` 是 `vim` 的配置文件,可以設置 vim 的配置,包括:**熱鍵**、**配色**、**語法高亮**、**插件** 等
* `Linux` 中 `vimrc` 有兩個位置,**家目錄下的配置文件優先順序更高**
```
/etc/vim/vimrc
~/.vimrc
```
* 常用的插件有:
* 代碼補全
* 代碼摺疊
* 搜索
* Git 集成
* ……
* 網上有很多高手已經配置好的針對 `python` 開發的 `vimrc` 文件,可以下載過來直接使用,或者等大家多 `Linux` 比較熟悉後,再行學習!