注:本文轉載自PRIN BLOG
原文鏈接:命令行界面 (CLI)、終端 (Terminal)、Shell、TTY,傻傻分不清楚?
0. 太長不看 TL;DR
- 命令行界面 (CLI) = 使用文本命令進行交互的用戶界面
- 終端 (Terminal) = TTY = 文本輸入/輸出環境
- 控制台 (Console) = 一種特殊的終端
- Shell = 命令行解釋器,執行用戶輸入的命令並返回結果
1. 什么是命令行界面?
命令行界面,通俗來講,就是你看過的那種滿屏幕都是字符的界面。
命令行界面(英語:Command-line Interface,縮寫:CLI)是在圖形用戶界面得到普及之前使用最為廣泛的用戶界面,它通常不支持鼠標,用戶通過鍵盤輸入指令,計算機接收到指令后,予以執行。
—— 摘自 Wikipedia
相信大家對於影視作品中出現的那種,某黑客/程序員/安全專家坐在電腦前猛敲鍵盤、屏幕上放眼望去全是滾動的字符的場景不會感到陌生。這種靠一行行命令的輸入輸出進行交互的用戶界面,就叫做命令行界面。
▲ 電影「黑客帝國」劇照
在圖形用戶界面 (GUI) 已經完全普及的今天,普通用戶在日常使用電腦的過程中幾乎不用手動輸入任何命令,大部分操作都是點點鼠標就能完成,而熟練使用命令行操作似乎已經成為高逼格的代名詞。
但事實上,現在依然有着很多的軟件開發者、系統管理員,或者是高級用戶在使用命令行界面操作計算機。其中很大一個原因,就是效率:在熟記命令的前提下,使用命令行界面往往要比使用圖形用戶界面來得快。
舉個栗子,我要把當前目錄下的(包括嵌套的子目錄)所有 *.tpl
文件的后綴名修改為 *.blade.php
,如果不使用命令行,該怎么做?手動修改肯定不至於,但也得去網上找找相關軟件,得要注意下載來源是否靠譜(像我這樣有點潔癖的選手還得去找綠色版),下載后還要手動指定文件路徑、重命名模板……
而使用命令行的話(這里以 Ubuntu 上的 Bash 為例),只需運行這么一句:
rename 's/\.tpl$/\.blade.php/' ./**/*.tpl
命令行操作的高效率等優點,也是現在許多圖形化的計算機系統依然沒有放棄提供命令行操作方式的原因。就連 Windows 都有自帶 cmd.exe
和 PowerShell 等命令行程序(事實上你在搜索「批量重命名」時,可以看到很多方案都是通過「Windows 命令提示符」實現的)。
2. 終端 —— 人與機器交互的接口
終端 (Terminal),其詞匯本身的意義為「終點站;末端;(電路)的端子,線接頭」。而在計算機領域,終端則是一種用來讓用戶輸入數據至計算機,以及顯示其計算結果的機器。
也就是說,終端只是一種用於與計算機進行交互的輸入輸出設備,其本身並不提供運算處理功能。
想要充分理解終端,我們得回溯歷史,去看看終端的起源。
2.1 歷史上的終端
在大型機 (Mainframe) 和小型機 (Minicomputer) 的時代里,計算機曾經非常昂貴且巨大,不像現在這樣人手一台。這些笨重的計算機通常被安置在單獨的房間內,而操作計算機的人們坐在另外的房間里,通過某些設備與計算機進行交互。這種設備就叫做 終端 (Terminal),也叫終端機。
▲ ASR-33 電傳打字機(圖片來源:Flickr - Marcin Wichary,CC-BY-2.0)
早期的終端一般是一種叫做 電傳打字機 (Teletype) 的設備。為啥呢?因為 Unix 的創始人 Ken Thompson 和 Dennis Ritchie 想讓 Unix 成為一個多用戶系統。多用戶系統就意味着要給每個用戶配置一個終端,每個用戶都要有一個顯示器、一個鍵盤。但當時所有的計算機設備都非常昂貴(包括顯示器),而且鍵盤和主機是集成在一起的,根本沒有獨立的鍵盤。
后來他們機智地找到了一樣東西,那就是 ASR-33 電傳打字機。雖然電傳打字機原本的用途是在電報線路上收發電報,但是它既有可以發送信號的鍵盤,又能把接收到的信號打印在紙帶上,完全可以作為人機交互設備使用。
而且最重要的是,價格低廉。:P
於是,他們把很多台 ASR-33 連接到計算機上,讓每個用戶都可以在終端登錄並操作主機。就這樣,他們創造了計算機歷史上第一個真正的多用戶操作系統 Unix,而電傳打字機就成為了第一個 Unix 終端。
想知道用電傳打字機做終端是一種怎樣的體驗?這里有一個 很炫酷的演示視頻。
2.2. 控制台 (Console) 是什么?
上面我們說過,在歷史上,終端是連接到計算機上的一種帶輸入輸出功能的外設。但是有一個終端與眾不同,它與計算機主機是一體的,是計算機的一個組成部分。這個特殊的終端就叫做 控制台 (Console)。
顧名思義,控制台是用於管理主機的,只能給系統管理員使用,有着比普通終端更大的權限。一台計算機上一般只有一個控制台,但是可以連接很多個終端。
▲ 左邊的是 Console,右邊的是 Terminal(圖片來源:帶你逛西雅圖活電腦博物館)
放在現在我們可能難以理解為什么會有控制台和終端的區分,不過就像上一節所說的,當時都是很多個用戶通過終端去訪問一台計算機,而專門管理那些大塊頭機器的系統管理員另有其人。普通用戶用的就是普通的終端,而系統管理員用的終端比較牛逼,所以就被叫做控制台啦(笑)。
不過隨着個人計算機的普及,控制台 (Console) 與終端 (Terminal) 的概念已經逐漸模糊。在現代,我們的鍵盤與顯示器既可以認為是控制台,也可以認為是普通的終端。當你在管理系統時,它們是控制台;當你在做一般的工作時(瀏覽網頁、編輯文檔等),它們就是終端。我們自己既是一般用戶,也是系統管理員。
因此,現在 Console 與 Terminal 基本被看作是同義詞。
2.3 字符終端與圖形終端
終端也有不同的種類。
字符終端 (Character Terminal) 也叫文本終端 (Text Terminal),是只能接收和顯示文本信息的終端。早期的終端全部是字符終端。字符終端也分為 啞終端 (Dumb Terminal) 和所謂的 智能終端 (Intelligent Terminal),因為后者可以理解轉義序列、定位光標和顯示位置,比較聰明,而啞終端不行。
▲ DEC VT100 終端(圖片來源:Flickr - Jason Scott,CC-BY-2.0)
DEC 公司在 1978 年制造的 VT100,由於其設計良好並且是第一批支持 ANSI 轉義序列與光標控制的智能終端,獲得了空前的成功。VT100 不僅是史上最流行的字符終端,更是成為了字符終端事實上的標准。
隨着技術的進步,圖形終端 (Graphical Terminal) 也開始出現在公眾的視野中。圖形終端不但可以接收和顯示文本信息,也可以顯示圖形與圖像。著名的圖形終端有 Tektronix 4010 系列。
不過現在專門的圖形終端已經極為少見,他們基本上已經被全功能顯示器所取代。
2.3. 終端模擬器 (Terminal Emulator)
隨着計算機的進化,我們已經見不到專門的終端硬件了,取而代之的則是鍵盤與顯示器。
但是沒有了終端,我們要怎么與那些傳統的、不兼容圖形接口的命令行程序(比如說 GNU 工具集里的大部分命令)交互呢?這些程序並不能直接讀取我們的鍵盤輸入,也沒辦法把計算結果顯示在我們的顯示器上……(圖形界面的原理我這里就不多說了,它們編程的時候圖形接口還在娘胎里呢!)
這時候我們就需要一個程序來模擬傳統終端的行為,即 終端模擬器 (Terminal Emulator)。
嚴格來講,Terminal Emulator 的譯名應該是「終端仿真器」。
對於那些命令行 (CLI) 程序,終端模擬器會「假裝」成一個傳統終端設備;而對於現代的圖形接口,終端模擬器會「假裝」成一個 GUI 程序。一個終端模擬器的標准工作流程是這樣的:
- 捕獲你的鍵盤輸入;
- 將輸入發送給命令行程序(程序會認為這是從一個真正的終端設備輸入的);
- 拿到命令行程序的輸出結果(STDOUT 以及 STDERR);
- 調用圖形接口(比如 X11),將輸出結果渲染至顯示器。
終端模擬器有很多,這里就舉幾個經典的例子:
- GNU/Linux:gnome-terminal、Konsole;
- macOS:Terminal.app、iTerm2;
- Windows:Win32 控制台、ConEmu 等。
▲ 我正在使用的終端模擬器:Hyper 與 wsl-terminal
在專門的終端硬件已經基本上僅存於計算機博物館的現代,人們通常圖省事兒,直接稱呼終端模擬器為「終端」。
2.4 終端窗口 (Terminal Window) 與虛擬控制台 (Virtual Console)
大部分終端模擬器都是在圖形用戶界面 (GUI) 中運行的,但是也有例外。
比如在 GNU/Linux 操作系統中,按下 Ctrl + Alt + F1,F2...F6 等組合鍵可以切換出好幾個黑不溜秋的全屏終端界面,而按下 Ctrl + Alt + F7 才是切換回圖形界面。不過不要被它們唬着了,雖然它們並不運行在圖形界面中,但其實它們也是終端模擬器的一種。
▲ 一個正在顯示系統啟動信息的虛擬控制台(圖片來源:hacktolive.org,GPLv2)
這些全屏的終端界面與那些運行在 GUI 下的終端模擬器的唯一區別就是它們是 由操作系統內核直接提供的。這些由內核直接提供的終端界面被叫做 虛擬控制台 (Virtual Console),而上面提到的那些運行在圖形界面上的終端模擬器則被叫做 終端窗口(Terminal Window)。除此之外並沒有什么差別。
當然了,因為終端窗口是跑在圖形界面上的,所有如果圖形界面宕掉了那它們也就跟着完蛋了。這時候你至少還可以切換到 Virtual Console 去救火,因為它們由內核直接提供,只要系統本身不出問題一般都可用(笑)。
3. 那么 TTY 又是什么?
簡單來說,tty 就是終端的統稱。
為什么呢?看了上面的 2.1 節的同學應該知道,最早的 Unix 終端是 ASR-33 電傳打字機。而電傳打字機 (Teletype / Teletypewriter) 的英文縮寫就是 tty,即 tty 這個名稱的來源。
由於 Unix 被設計為一個多用戶操作系統,所以人們會在計算機上連接多個終端(在當時,這些終端全都是電傳打字機)。Unix 系統為了支持這些電傳打字機,就設計了名為 tty 的子系統(沒錯,因為當時的終端全都是 tty,所以這個系統也被命名為了 tty,就是這么簡單粗暴),將具體的硬件設備抽象為操作系統內部位於 /dev/tty*
的設備文件。
為什么要把電傳打字機這個硬件設備抽象成「tty 設備」文件呢?有興趣的同學可以去了解一下 Unix 操作系統中 Everything is a file 的概念。
▲ 還記得上面我們說過的特殊的終端,也就是通過 Ctrl + Alt + F1-6 呼出的那些虛擬控制台 (Virtual Console) 嗎?其對應的就是上圖中的 tty1
到 tty6
。
隨着計算機的發展,終端設備已經不再限制於電傳打字機,但是 tty 這個名稱還是就這么留了下來。久而久之,它們的概念就混淆在了一起。所以在現代,tty 設備就是終端設備,終端設備就是 tty 設備,無需區分。
由於早期計算機上的 串行端口 (Serial Port) 最大的用途就是連接終端設備,所以當時的 Unix 會把串口上的設備也同樣抽象為 tty 設備(位於
/dev/ttyS*
)。因此,現在人們也經常將串口設備稱呼為 tty 設備。
在 tty 子系統中后來還衍生出了 pty、ptmx、pts 等概念,這里就不詳細展開了。有興趣的同學可以參考一下這篇文章:Linux TTY/PTS 概述。
4. Shell —— 提供用戶界面的程序
大家都知道,操作系統有一個叫做 內核 (Kernel) 的東西,它管理着整台計算機的硬件,是現代操作系統中最基本的部分。但是,內核處於系統的底層,是不能讓普通用戶隨意操作的,不然一個不小心系統就崩潰啦!
但我們總還是要讓用戶操作系統的,怎么辦呢?這就需要一個專門的程序,它接受用戶輸入的命令,然后幫我們與內核溝通,最后讓內核完成我們的任務。這個提供用戶界面的程序被叫做 Shell (殼層)。
其實 Shell 只是提供了一個用戶操作系統的入口,我們一般是通過 Shell 去調用其他各種各樣的應用程序,最后來達成我們的目的。比如說我們想要知道一個文件的內容,我們會在 Shell 中輸入命令
cat foo.txt
,然后 Shell 會幫我們運行cat
這個程序,cat
再去調用內核提供的open
等系統調用來獲取文件的內容。雖然並不是 Shell 直接去與內核交互,但廣義上可以認為是 Shell 提供了與內核交互的用戶界面。
至於為什么叫做 Shell,看下圖就知道啦。是不是很像一層殼呢?
Shell 通常可以分為兩種:命令行 Shell 與 圖形 Shell。顧名思義,前者提供一個命令行界面 (CLI),后者提供一個圖形用戶界面 (GUI)。Windows 下的 explorer.exe
就是一個典型的圖形 Shell(沒錯,它確實是,因為它接受來自你的指令,並且會幫你與內核交互完成你的指令)。
常見或歷史上知名的命令行 Shell 有:
- 適用於 Unix 及類 Unix 系統:
- sh (Bourne shell),最經典的 Unix shell;
- bash (Bourne-Again shell),目前絕大多數 Linux 發行版的默認 shell;
- zsh (Z shell),我個人最喜歡的 shell;
- fish (Friendly interactive shell),專注於易用性與友好用戶體驗的 shell;
- Windows 下的 cmd.exe (命令提示符) 與 PowerShell。
還有其他各種五花八門的 Shell 程序,這里就不一一列舉了,有興趣的自己去搜一搜吧。:P
5. Shell 與終端的分工
現在我們知道,終端干的活兒是從用戶這里接收輸入(鍵盤、鼠標等輸入設備),扔給 Shell,然后把 Shell 返回的結果展示給用戶(比如通過顯示器)。而 Shell 干的活兒是從終端那里拿到用戶輸入的命令,解析后交給操作系統內核去執行,並把執行結果返回給終端。
不過 Shell 與終端的分工有一些容易混淆的地方,這里以例子進行說明:
- 終端將用戶的鍵盤輸入轉換為控制序列(除了字符以外的按鍵,比如
左方向鍵
→^[[D
),Shell 則解析並執行收到的控制序列(比如^[[D
→將光標向左移動
); - 不過也有例外,比如終端在接收到 Ctrl + C 組合鍵時,不會把這個按鍵轉發給當前的程序,而是會發送一個
SIGINT
信號(默認情況下,這會導致進程終止)。其他類似的特殊組合鍵有 Ctrl-Z 與 Ctrl-\ 等,可以通過stty -a
命令查看當前終端的設置。
- Shell 發出類似「把前景色改為紅色(控制序列為
\033[31m
)」「顯示foo
」等指令; - 終端接收這些指令,並且照着 Shell 說的做,於是你就看到了終端上輸出了一行紅色的
foo
。
- 除非被重定向,否則 Shell 永遠不會知道它所執行命令的輸出結果。我們可以在終端窗口中上下翻頁查看過去的輸出內容,這完全是終端提供的 feature,與 Shell 沒有半毛錢關系;
- 命令提示符 (Prompt) 是一個完全的 Shell 概念,與終端無關;
- 行編輯、輸入歷史與自動補全等功能是由 Shell 提供的(比如 fish 這個 Shell 就有着很好用的歷史命令與命令自動補全功能)。不過終端也能自己實現這些功能,比如說 XShell 這個終端模擬器就可以在本地寫完一行命令,然后整條發送給遠程服務器中的 Shell(在連接狀況不佳時很有用,不然打個字都要卡半天);
- 終端中的復制粘貼功能(Shift + Insert 或者鼠標右鍵等)基本上都是由終端提供的。舉個例子,Windows 默認的終端對於復制粘貼的支持很屎,而換一個終端(例如
ConEmu
)后就可以很好地支持復制粘貼。不過 Shell 以及其他命令行程序也可以提供自己的復制粘貼機制(例如 vim)。
6. 總結
計算機史這玩意,有趣是挺有趣的,就是查起資料來太費腦子。
為了不誤人子弟,在這篇博文寫作的過程中我也查閱了各種各樣的文檔和史料,力求內容的准確性。不過能力所限,如果文章中仍有出現謬誤,歡迎在下方評論區批評指正。
7. 參考鏈接
- 命令行界面 - Wikipedia
- What is the exact difference between a ‘terminal’, a ‘shell’, a ‘tty’ and a ‘console’?
- Why is a virtual terminal “virtual”, and what/why/where is the “real” terminal?
- 終端,Shell,“tty” 和控制台(console)有什么區別? - 知乎
- 你真的知道什么是終端嗎? - Linux 大神博客
- 終端 - Wikipedia
- Terminal emulator - Wikipedia
- console(4): console terminal/virtual consoles - Linux man page
- Linux TTY/PTS 概述 - SegmentFault
- Linux TTY framework(1)_基本概念
- Shell (computing) - Wikipedia
- 學習 bash shell - 鳥哥的 Linux 私房菜
- Ubuntu Manpage: 控制終端代碼 - Linux 控制終端轉義和控制序列
(完)