本文共6100餘字,預計閱讀時間16分鐘,本文知乎連接:Linux Cygwin知識庫(一):一文搞清控制台、終端、shell概念,本文同步發佈於微信公眾號(偽碼人)。

關注賬號學習了解更多Cygwin、Linux技術。

目錄

0x00 關係概覽

0x01 控制台、終端、串口終端

0x02 虛擬終端、終端模擬器、偽終端

0x03 Shell

參考


控制台、終端、shell是命令行界面(CLI)系統中極重要的幾個概念,而計算機軟體系統中最普遍的思想是分層,這幾個事物就在不同層次中,搞清楚概念才能理解軟體程序工作在那一層,本文將帶你梳理清楚控制台、終端、shell相關概念及其關係。

0x00 關係概覽

先總體上簡要概括這幾個名詞在計算機系統中所扮演的角色。

控制台、終端、虛擬終端是一類輸入輸出設備的總稱,擁有將用戶指令輸入給操作系統和將操作系統返回結果輸出給用戶的基本功能,電傳打字機(teletypewriter,縮寫為tty)是該類設備的具體實例。終端模擬器(Terminal Emulator)是一類應用程序,用來模擬終端設備的功能,未具體說明情況下,「終端」泛指真實終端設備或終端模擬器。偽終端(pseudo tty,縮寫為pty)是UNIX/Linux內核中驅動程序模塊,是一個軟體中間層,用於克服真實終端設備在現代應用場景中的不足。

Shell是UNIX/Linux系統中最為重要的應用程序之一,負責解釋執行用戶指令,列印結果,和用戶交互,進行著REPL(Read-Evaluate-Print Loop)。sh、bash、zsh、fish等都是Shell的具體實例。

系統內核接管計算機資源,設備和程序在系統內核的調配下運轉,他們之間的關係可用下圖表示。用戶實際用到的是具體程序,是難以感知內核的存在的,所以看起來就像是Shell在幫助用戶調用程序。

終端、Shell、系統內核與用戶的關係示意

0x01 控制台、終端、串口終端

計算機發明初期很貴且龐大,一台計算機佔地要數間房子,被放置在玻璃房門裡,一般人「可遠觀而不可褻玩」。如此的龐然大物有一個專門的操作台,陳列各種儀錶盤、指示燈、按鈕、電線,操作人員通過這個操作台控制計算機的啟動、運行、停止,結果同時反饋到操作台,這個操作台就叫「控制台(Console)」。這時的計算機真的就是跟工廠機器一樣,需要專業的師傅專門操作,師傅叫做「操作員(Operator)」。

早期的計算機控制台(圖片來源於網路)

控制台可以實現對計算機的完全操控,用來管理計算機,但不方便給用戶服務。後來計算機技術發展,計算能力不斷提升並出現了多用戶操作系統(特別是UNIX),允許每個用戶通過終端設備(Terminal)與主機連接,操作系統管理員給每個用戶分配一個賬戶,「登錄」到系統獲得計算機使用權,這時計算機才算實現了服務用途。

按照計算機組成劃分,終端設備僅僅是一個IO外設——將用戶的指令輸入給主機,將主機的返回結果輸出給用戶,而電傳打字機(teletypewriter)能夠完成這一功能。UNIX/Linux系統常將登陸到系統的終端抽象為/dev/ttyN(N為數字),tty即源自teletypewriter縮寫。但是電傳打字機的輸出印在紙上,用戶輸入的字元就像打字機一樣也是刪不掉的,而且用戶輸入什麼就會立刻傳給主機。從1970年代末期開始,電子視頻終端(video terminal)開始取代電傳打字機成為主流的終端設備,帶緩存功能,允許用戶在傳給主機之前修改輸入信息,1978年Digital公司生產的VT100時至今日仍然是終端的事實標準。

電傳打字機(圖片來源於網路)
VT100(圖片來源於網路)

UNIX/Linux內核中有3個模塊共同支持終端設備:讀寫函數、終端行規程(terminal line discipline,也有譯作「終端線路規程」)、字元設備驅動。應用程序通過tty_read、tty_write等函數對終端字元設備發起讀寫操作,終端行規程作用類似於過濾器,對讀寫的字元做特殊處理,比如將按鍵Ctrl-C、Ctrl-Z等特殊字元解釋成相關信號發給前台進程,並不讓應用程序讀到,真正可讀寫的字元才會進一步傳遞給應用程序或tty字元設備驅動程序,驅動程序再去操作設備本身。終端行規程可看作是人機交互的通用規範。

tty字元設備驅動程序維護著輸入和輸出兩個隊列,終端按鍵輸入的字元經終端行規程處理後送到輸入隊列,應用程序按先入先出原則在隊列中讀到字元;應用程序發起寫操作,輸出的字元經行規程處理後送到輸出隊列,驅動程序按先入先出原則將輸出隊列的字元在終端上顯示出來。如果終端配置成回顯(Echo)模式,那麼輸入隊列中字元被送給應用程序的同時送到輸出隊列,因此用戶在終端按鍵的時候,字元不僅被應用程序讀到,同時也在終端回顯。回顯(Echo)正是終端通常設置的工作模式。

內核實現的終端設備讀寫函數、行規程及驅動(圖片來源:UNIX環境高級編程)

終端設備通過顯示卡、鍵盤口等介面與主機直連,終端設備的驅動程序實現了紛繁複雜的IO模式、規範等,以便命令行程序充分利用終端設備的各種功能。

後來計算機發展出串列埠(Serial Port),彼時串口的最大用途就是連接終端,計算機就把連接到串口的外設看作字元設備,外設稱為「串口終端(Serial Port Terminal)」,串口在Linux系統中對應著設備/dev/ttyS1、/dev/ttyS2......等,Windows下COM1、COM2概念相對應,對串口的讀寫操作最後都反映到與之相連的外設上。

0x02 虛擬終端、終端模擬器、偽終端

如今,PC已成為消費級電子產品,電傳打字機、電子視頻終端已基本淘汰,控制台、終端不再是各自獨立的外設,PC上的鍵盤、顯示器被整合為控制台/終端。

一台PC通常只有一套鍵盤和顯示器,也就是只有一套物理終端設備,Linux內核將這一套鍵盤和顯示器映射為6個字元終端設備文件,即/dev/tty1~tty6,稱為「虛擬終端(Virtual Terminal)」,可通過Ctrl-Alt-F1~F6切換。/dev/tty0則指向用戶當前正在使用的虛擬終端,如用戶切換到/dev/tty4,那麼/dev/tty0就指向/dev/tty4。

終端模擬器(Terminal Emulator)是基於系統中已有的鍵盤、顯示驅動而構建的圖形界面程序,其根本用途只有一個——模擬電子視頻終端的功能,前文所述的VT100就是被廣泛模擬的對象,實際支持的操作比真實終端設備要高級得多。xterm是X11圖形窗口系統(被很多Linux、UNIX發行版採用)下的標配終端模擬器。

終端、虛擬終端、串口終端是有真實物理設備相對應的,一方面數量有限制,另一方面在遠程執行主機上的應用程序(比如sh、vi等)時,終端雖然通過基於TCP/IP協議的socket介面與主機連接了,但遠程主機上的程序的標準輸入、標準輸出、標準錯誤無法關聯到socket上,同時主機上的程序只有對終端設備操作才能正常運行,socket無法提供和終端設備兼容的IO模式、規範等。

那麼,該怎麼彌補這之間的差異?又雙?叒叕一次祭出David Wheeler大神的名言:

「All problems in computer science can be solved by another level of indirection(計算機科學領域的任何問題都可以通過增加一個間接的中間層來解決)」。

David Wheeler ( 圖片來源:wikipedia.org)

偽終端(pseudo tty,縮寫為pty)就是這樣一個中間層,是UNIX/Linux內核中一對雙向互聯的設備,分為主設備(pty master)和從設備(pty slave),也稱作「偽終端對(pty pair)」。回到上面提到的執行遠程主機上應用程序的場景,有了偽終端設備支持,本地終端並不直接和目標程序連接,而是通過「代理程序」替它操作: ① 「代理程序」進程同時打開socket和pty主設備,監控這兩路數據; ② 「目標程序」進程(通常是「代理程序」創建)則打開pty從設備,而pty主從設備互聯,這樣他們充當了「代理程序」進程和「目標程序」進程的雙向管道, pty從設備表現與真實終端設備完全一致, 「目標程序」進程的標準輸入、標準輸出、標準錯誤均能關聯到pty從設備; ③ 本地的指令通過socket發送到代理程序進程,代理程序進程將socket上的數據寫入pty主設備,最後被映射到目標程序進程對pty從設備的標準輸入; ④ 「目標程序」進程對pty從設備的標準輸出、標準錯誤,最後傳送到代理程序,並通過socket返回到本地。

偽終端設備工作原理示意

在實際應用場景中,「代理程序」可能是ssh/telnet server,目標程序可能是shell,本地用戶就通過本地主機ssh/telnet客戶端程序遠程登錄到主機shell。 從上圖和文字可以看出:「代理程序」名副其實地主要起著代理作用,雙向傳遞數據,這個流程能走通的關鍵是pty從設備能夠和真實終端設備表現一致。從功能上講,偽終端取代了原始終端設備與主機連接模型中的通信線纜,而且是在內存中實現高速通信 ,設備由於不是真實硬體,系統中打開的數量名義上可以無限(內核可配置)。

對於本地主機的終端模擬器,除了模擬終端本身還承擔著上圖「代理程序」的角色,「目標程序」則可能是某個登陸Shell,如下文要提及的bash、zsh,也可能是上文提及的ssh/telnet客戶端程序等。

支持偽終端設備的終端模擬器工作原理示意

歷史上,UNIX系統偽終端的著名實現有System V(UNIX 98)和BSD兩種風格,而且介面互不兼容,但是前者更易使用,Single Unix Specification V3(2004版)所規定的偽終端是基於System V(UNIX 98)介面的,現代的許多UNIX以及Linux同時支持兩者。

由於設計理念不同,Windows內核不支持Single Unix Specification中規定對終端、偽終端,而是提供兩大類應用程序的API:Console應用程序和GUI應用程序。前者在Windows系統自帶的命令提示符窗口中,由cmd解釋執行。Windows系統上有多種優秀的第三方終端模擬器,利用Console API、Cygwin API等手段在用戶空間模擬pty特性。2018年,微軟在Windows 10新版本上開始搭載Windows Pseudo Console(ConPTY)API,提供類似於UNIX偽終端設備的支持。

0x03 Shell

終端自身並不執行用戶輸入的命令,它只是負責把輸入的內容傳送到主機系統,並把主機系統返回的結果呈現給用戶。負責解釋執行用戶輸入的命令並返回結果的,正是Shell!它是溝通用戶和系統內核的中間橋樑。

從這個功能講,廣義上的Shell可以是圖形界面的也可以是命令行界面的。比如Windows上的Explorer,雙擊文件名為什麼可以讓一個程序打開這個文件?其實可以理解為Explorer捕捉到了「滑鼠雙擊文件名」這個事件,然後根據文件名去請求Windows內核啟動了一個關聯程序,並傳入相關參數(文件名等信息),然後這個程序自己再「打開」用戶雙擊的文件,呈現到屏幕上。Windows上運行「命令提示符」時,在任務管理器中可以看到運行了兩個進程:Console Windows Host和cmd,前者是終端模擬器,後者則是Shell程序。除了圖形、命令行交互,未來還可能出現更加高級的Shell,比如語音、動作等等。

Windows命令提示符相關進程

狹義的Shell僅指字元界面的命令解釋器,在UNIX/Linux系統上廣泛應用,所做的工作主要是: ① 讀入用戶輸入(Read); ② 解釋執行(Evaluate); ③ 列印執行結果和提示符(Print); ④ 回到①循環(Loop)。

這種工作方式被稱為互動式Shell(Interactive Shell),Shell通常還支持批處理方式(Batch),用戶提前寫好要執行的命令,形成腳本(Shell Script),Shell一次性把腳本中的命令執行完。

UNIX/Linux系統上存在多種字元界面的Shell,比較著名的有:

  • sh(Bourne Shell),1977年由Steve Bourne開發,成為各種UNIX的標配,兼容POSIX的sh在1992年開發;
  • csh(C Shell),1978年由Bill Joy開發,隨BSD UNIX發布,語法和C語言相似;
  • tcsh(TENEX C Shell),1983年開發,兼容POSIX是csh的增強版本,支持命令補全等特性,在FreeBSD、Mac OS X等系統上替代csh;
  • ksh(Korn Shell),由David Korn開發,兼容sh並添加了很多csh引入的特性,是現代各種UNIX的標配,這些系統上sh實際是指向ksh的符號鏈接;
  • bash(Bourne Again Shell),1989年由GNU項目開發,與POSIX標準保持一致,同時兼容sh,是Cygwin、Linux系統的標配,這些系統上sh實際是指向bash的符號鏈接;
  • zsh(Z Shell),1990年由Paul Falstad開發,在兼容bash基礎上引入ksh、tcsh的多種特性,如自動補全、智能提示等,配置高度自由,被稱為終極shell;
  • fish(Friendly Interactive Shell),2005年開發,目標是易於使用、記憶命令,和zsh是對手。

參考

  • W.Richard Stevens,Stephen A.Rago·Advanced Programming in the UNIX Environment[M]·尤晉元,張亞英,戚正偉 譯,2005·
  • Michael Kerrisk·The Linux Programming Interface : A Linux and UNIX System Programming Handbook[M]·孫劍,許從年,董健 孫余強 譯,2014·
  • en.wikipedia.org/wiki/P
  • en.wikipedia.org/wiki/C
  • Windows Command-Line: Introducing the Windows Pseudo Console (ConPTY)

更多閱讀

專欄 :Cygwin修鍊?

zhuanlan.zhihu.com
圖標
上一篇: Cygwin系列(六):使用Cygwin常見問題及應對?

zhuanlan.zhihu.com
圖標
其他: GNU Wget 爬蟲?試一試?

zhuanlan.zhihu.com
圖標


本文對你有幫助?請轉發分享,歡迎關注與留言交流

?本文為原創文章,如需轉載請私信知乎賬號silaoA或聯繫公眾號偽碼人(We_Coder)。

都看這裡了,不妨點個贊再走唄


推薦閱讀:
相关文章