當你打開終端並輸入命令時會發生什麼?(下) 哈嘍大家好,我是鹹魚 我們先來大致回顧一下文章《當你打開終端並輸入命令時會發生什麼?(上)》的內容 終端設備是由電傳打字機演變過來的,電傳打字機通過物理線與大型電腦連接在一塊來實現輸入輸出 如上圖,分別是二戰時期的電傳打字機和西門子 “Fernschei ...
當你打開終端並輸入命令時會發生什麼?(下)
哈嘍大家好,我是鹹魚
我們先來大致回顧一下文章《當你打開終端並輸入命令時會發生什麼?(上)》的內容
終端設備是由電傳打字機演變過來的,電傳打字機通過物理線與大型電腦連接在一塊來實現輸入輸出
如上圖,分別是二戰時期的電傳打字機和西門子 “Fernscheiber 100” 電傳打字機
隨著技術的不斷發展(尤其是顯示技術),帶顯示屏的終端設備隨之誕生
而現在隨著個人電腦的普及,出現了基於屏幕顯示的圖形用戶界面(GUI),演變成了現在的電腦終端
現在的終端大多都是電腦上的一個應用程式,它們通常被稱為終端模擬器,充當用戶與操作系統交互的界面(比如說 Linux 中的 Xterm、Xshell,Windows 中的控制台),而不必使用專門的終端。輸出系統是屏幕,輸入系統是鍵盤
以 Linux 為例,當我們打開終端時,通常會啟動一個 shell 進程,用於與用戶交互。用戶在終端中輸入的命令將傳遞給 shell 進程,然後由 shell 解釋和執行這些命令
這個過程包括將用戶輸入的命令解析為操作系統可以理解的指令,執行這些指令,並將執行結果返回給終端顯示給用戶
輸入命令
當我們在終端中輸入命令時,鍵盤輸入的字元會被轉換成相應的字元編碼(比如說 backspace
鍵被轉譯成 ASCII 字元 0x08
)
這些字元通過終端寫入到 PTY leader,接著 TTY driver 從 PTY leader 中讀取字元並存儲到 line discipline 中(line discipline 為 PTY 兩端之間的中間緩衝區)
不但如此,line discipline 還負責解釋來自 PTY leader 的字元然後根據自己的規則去處理它們(比如進行回退、刪除字元等,或者處理特殊字元)
舉個例子,line discipline 收到 backspace
時,它會根據自己的規則解釋成 ERASE 字元,然後進行編輯,方法是刪除最後一個字元
接著將刪除操作返回給 PTY leader,這樣終端就可以從 PTY leader 那裡讀取到更改並將其反映在終端顯示中
需要註意的是,上面這段過程里字元還沒有被寫入到 PTY follower 中,只是處在【編輯】部分
當我們在鍵盤敲下 CTRL+C
時,line discipline 會解釋成 INTR
(INTERRUPT 的縮寫),這時候就會向 PTY follower 發送一個 SIGINT 信號去中斷在前臺運行的任何進程
如果不是特殊字元(比如輸入 ls
),line discipline 會將字元返回給 PTY leader,終端程式讀取並顯示在屏幕上,這就是為什麼你在鍵盤敲一個字元,顯示器就會顯示一個字元(echo 功能)
現在 shell 進程也會緩衝用戶的輸入,以實現一些高級的功能:比如命令歷史記錄或 tab 鍵自動補全
執行並解析命令
當我們輸入完命令之後,就要按下回車鍵(Enter)來執行命令了
一旦按下回車鍵,line discipline 解釋為換行字元(newline),通常表示為 NL
。
然後一併將用戶的命令轉發到 PTY follower ,而 shell 進程跟 follower 相連,shell 拿到命令之後就會去解析並執行
當 shell 進程接收到用戶的輸入和換行符時,它會開始解析並執行命令。這個過程包括命令解析、查找可執行文件或內置命令,以及執行相應的操作
首先對命令解析成一個一個 token 併進行語法/語義分析,以 ls
命令為例:
ls > foo.txt
:正確ls >
:語法不正確,>
後面缺少內容ls | foo.txt
:語義不正確,管道的兩端都需要是可運行的進程
然後接著解析那些不是 shell 關鍵字或者路徑的 token,shell 需要知道這些 token 的含義,所以 shell 會去根據下麵幾個部分去遞歸查找 token 引用的內容:
- aliases:命令別名,通常用於縮寫複雜的命令(例如
alias ll="ls -lh"
) - function:函數
- environment variables:環境變數
- builtins:shell 內嵌命令(例如
cd
pwd
exit
kill
) - PATH executables:shell 可以找到(通過
$PATH
變數)並運行的外部命令
我們可以通過 type
命令知道對應的類型
[root@minion1 ~]# type ll
ll 是 'ls -l --color=auto' 的別名
[root@minion1 ~]# type cd
cd 是 shell 內嵌
[root@minion1 ~]# type python
python 是 /usr/bin/python
與 shell 內嵌命令不同的是,可執行命令是單獨的程式或腳本文件,具有執行許可權,可以作為單獨的進程執行
當用戶在 shell 中輸入一個命令時,shell 會查找可執行文件的位置,併在找到後創建一個新的子進程來運行該可執行文件,並將相應的命令參數傳遞給這個新的子進程
我們可以通過 pstree
命令來查看進程之間的關係
返回輸出
當 shell 執行完命令之後,把生成的輸出寫入到 PTY follower ,接著傳到 line discipline 中,line discipline 不會處理這些輸出,而是轉發給 PTY leader,然後終端就會讀取並顯示到屏幕上
參考文章:https://www.warp.dev/blog/what-happens-when-you-open-a-terminal-and-enter-ls