Linux前世今生(三)Unix Shell

文 | 諸葛運帷 豹頭環眼的飛哥


Shell是什麼?它是怎麼來的?

Linux前世今生(三)Unix Shell

好像幾乎沒有人能很清晰的解答這個問題。有人說,Shell(又被稱為殼)是相對於Kernel(核)來說的。Kernel是操作系統的核心組件,它是操作系統程序的一部分,駐留在內存當中,處理應用程序與計算機硬件之間的交互。那麼Shell就是計算機用戶與應用程序之間的"一層物質“,當用戶登錄系統後,Shell也會駐留到內存當中,處理用戶與應用程序之間的交互。因此,Shell會有”圖形“Shell與”命令行”Shell之分。

這種說法,似乎有那麼一些道理,但仔細想想,又會讓人覺得迷糊。我們知道,很多情況下,用戶直接與應用程序打交道就好了,何必多此一舉在中間加一個“殼”呢?讓我們回顧一下自己經常使用的應用軟件,特別是具有圖形交互界面的軟件,有多少聲稱自己通過“xx殼”與用戶進行交互呢?

所以,我們要弄明白“殼”到底是什麼,需要回到一切的最開端--MULTICS。

至於MULTICS是什麼,這裡不再贅述。請查看本系列的頭兩篇文章。

在MULTICS的“博物館網站”上,有一段對“殼”的描述

The Multics command processor used to be called the shell. This program is passed a command line for execution by the listener; it parses the line into a command name and arguments, locates the command and initiates it, and calls the command program with arguments that are PL/I character strings. It is simple to replace the default system supplied shell with a user-provided program, by calling cu_$set_cp (see abbrev).

簡單翻譯如下:

MULTICS的命令處理器曾經被稱作“Shell”。它本身是一個程序。偵聽器(另外一個程序)把命令行發送給Shell程序,隨後該程序將命令行拆解為”命令名“與”參數“。接著,它根據命令名找到對應要執行的程序,對被執行的程序進行初始化,然後將剛才解析出來的參數傳給該程序並執行。由於Shell本身是個程序,所以它可以被任何用戶自己開發的程序所代替。

Louis Pouzin(路易·普津)是最早提出“Shell”概念的人。作為MIT計算中心的專家,他於1963年左右在CTSS上開發了一個叫做“RUNCOM”的程序。他之所以開發RUNCOM,是因為他腦海中突然閃過的一個念頭:“命令”是否應該模塊化,調用命令是否能夠像執行子程序那樣簡單?

據Louis Pouzin的敘述,由於種種原因,他並沒有太多參與到MULTICS當中。但他仍然對“命令模塊化”的理想念念不忘。Christopher Strachey -- 一位來自於英國的計算機科學牛人(克里斯·託弗,“虛擬化”概念的發明人),曾在MIT待過一段時間。在那期間,Christopher Strachey提出了一個“宏生成器”的概念。這大大啟發了Louis Pouzin。後來,他提交了一篇論文,用於闡述在MULTICS應當如何實現“命令模塊化”。在這篇論文當中,Louis Pouzin首次提出了“Shell”這個單詞。

Linux前世今生(三)Unix Shell

當然,MULTICS並沒有迎來爆發。它只是一個奠基者,所以他的很多創意都只是起到了“拋磚引玉”的作用,Shell也是如此。

在那之後,肯·湯普遜繼承了MULTICS的衣缽,並一手締造了Unix。同時,被他順帶手從MULTICS拿過來的,還有Shell。

肯·湯普遜的遊戲癮很大。

為了能夠從PDP-7上運行自己從MULTICS上開發的Space Travel遊戲(參考上本系列上一篇),肯·湯普遜在不到一個月的時間完成了操作系統的雛形,並用了將近一週的時間開發了操作系統的Kernel、文本編輯器、編譯器,同時還移植了Shell。而這些都是基於PDP-7 的彙編語言實現的。

當然,這些並不能算是真正的Unix,同時肯·湯普遜開發的Shell也不能算是真正的Unix Shell,因為它只是在湯普遜的“玩具”PDP-7上開發實現的。

1971年,肯·湯普遜的團隊發佈了第一個“正式”的Shell版本--V6 shell,它也被後人稱為“Thompson shell”。這個Shell是基於C實現的,它很精簡,只有九百多行代碼。在這個Shell版本中,第一次引入了”重定向“與”管道“(也就是、>>及|)。同時,還支持以分號(;)或”與“符號(&)分隔的命令序列。

Thompson shell的最大短板就是--它缺少腳本能力。它唯一能做到的事情就是執行命令並輸出執行結果。

Thompson shell的繼任者是Mashey shell(PWB shell)。它的作者是John Mashey。Mashey shell在Thompson shell的基礎上擴展了腳本語言,並支持變量定義。它還內置了條件分支與循環控制。Mashey shell伴隨Unix5發行,在Unix6中仍然作為Thompson shell的備選Shell。

對於“腳本”這個概念,也是挺讓人模稜兩可的。它到底是一種程序,還是一種編程語言呢?

在某百科上,對於腳本(script)是這樣描述的:

A>

簡單翻譯一下:

腳本或腳本語言是一種運行時環境下的編程語言。它的目的是批量執行自動化任務(當然這些任務也可以人為的一條一條的執行)。腳本語言通常是解釋型的(而非編譯型的)。

Primitives are usually the elementary tasks or API calls[clarification needed], and the language allows them to be combined into more programs. Environments that can be automated through>

腳本的行為通常包括一些基本的管理任務或API調用。腳本語言可以將這些管理任務或API進行組合,形成完整的(自動化)程序。通常來說,應用程序、網頁、瀏覽器、支持Shell的操作系統、嵌入式系統、還有各種各樣的遊戲..都可以通過腳本實現一些運行時的自動化程序。腳本語言可以被認為是服務於特定環境並專注於特定業務領域的編程語言。在應用程序進行開發時,腳本也被認作是一種(服務於核心程序框架之外的)擴展語言。

基於上面的分析,腳本最核心的三個方面就是:批量、自動化、任務與API的組合。因此,腳本本質上是一種效率工具。有了這個工具,用戶可以在不瞭解應用程序底層邏輯的情況下,實現一種更高維度的“應用程序擴展”或”自動化作業“。我們拿遊戲來說,遊戲程序本身的開發是一件非常繁瑣的事情,包括遊戲畫面的展示、遊戲與玩家的交互等。然而一旦遊戲的基礎框架被搭建起來之後,遊戲的二次開發者們就可以通過“腳本”實現各種各樣的遊戲劇情,從而為遊戲的玩家們帶來各種各樣新奇有趣的遊戲體驗。這是一種高效的“二次開發”過程。因為在這個過程中,遊戲框架內部的複雜元素都被隱藏起來了。

讓我們回到Shell的話題。在對“腳本”這個概念進行深入研究後,我們對“Mashey shell相較於Thompson shell有了怎樣的提升”這件事上有了更加深刻的理解。有了腳本,有了邏輯分支,有了流程控制,運維人員和開發者們終於在不需要了解操作系統內部實現細節的情況下有了大展拳腳的機會。

此後,1979年由Stephen Bourne開發的Bourne shell橫空出世,在1979年發行的Unix7中,取代了Mashey shell,坐上了Unix Shell的頭把交椅。同時,它也把操作系統Shell帶到了一個新的高度。

Bourne shell是在Mashey shell基礎上開發的,並進行了很多重大改進,以至於它與我們今天常用的Bash Shell的差別已經不算大。

Stephen Bourne是一個無聊的英國老頭兒,除了學術方面造詣頗深之外,他在職業或學業生涯當中實在沒有什麼趣談。

Linux前世今生(三)Unix Shell

在這裡,我們把Bourne shell的一些主要特性羅列如下。限於作者的耐性,這裡就不一一翻譯了。

Scripts can be invoked as commands by using their filename (腳本可通過文件名調用)

May be used interactively or non-interactively(支持交互式或非交互式)

Allows both synchronous and asynchronous execution of commands(同步與異步)

Supports input and output redirection and pipelines(輸入輸出重定向)

Provides a set of built-in commands(一些內置命令)

Provides flow control constructs, quotation facilities, and functions.(腳本的流程控制、引用與函數)

Typeless variables(無類型變量)

Provides local and global variable scope(本地及全局變量)

Scripts do not require compilation before execution(腳本執行前不需要預編譯)

Does not have a goto facility, so code restructuring may be necessary(不支持goto)

Command substitution using back quotes: `command`.(單引號執行命令)

Here documents using << to embed a block of input text within a>

"for ~ do ~ done" loops, in particular the use of $* to loop over arguments, as well as "for ~ in ~ do ~ done" loops for iterating over lists.(支持for循環)

"case ~ in ~ esac" selection mechanism, primarily intended to assist argument parsing.(支持case分支)

sh provided support for environment variables using keyword parameters and exportable variables.(支持環境變量)

Contains strong provisions for controlling input and output and in its expression matching facilities.

Built-in test command – System III shell (1981)

# as comment character – System III shell (1981)

Colon in parameter substitutions "${parameter:=word}" – System III shell (1981)

continue with argument – System III shell (1981)

cat <

Functions and the return builtin – SVR2 shell (1984)

Built-ins unset, echo, type – SVR2 shell (1984)

Source code de-ALGOL68-ized – SVR2 shell (1984)

Modern "$@" – SVR3 shell (1986)

Built-in getopts – SVR3 shell (1986)

Cleaned up parameter handling allows recursively callable functions – SVR3 shell (1986)

8-bit clean – SVR3 shell (1986)

Job control – SVR4 shell (1989)

Multi-byte support – SVR4 shell (1989)

從Bourne shell開始,Shell“市場”開始了百家爭鳴時代。這裡麵包括Korn shell(ksh)、Almquist shell (ash)以及最著名的Bourne Again Shell (or Bash)。一個比較個別的shell產品是C shell (csh),它讓Shell的腳本看上去更像用C語言編寫。下圖是Shell的族譜。

Linux前世今生(三)Unix Shell

https://www.multicians.org/mgs.html

https://developer.ibm.com/technologies/linux/tutorials/l-linux-shells/#artrelatedtopics

http://linuxcommand.org/lc3_adv_othershells.php




Linux前世今生(三)Unix Shell

運維就是服務的創造者和維護者!

IT運維之眼-“諸葛運帷” 業務級運維監控管理平臺,企業端到移動端的運維監控整體解決方案。系統以業務系統監控為主線,基於“業務、軟件、網絡、設備、動環”多個監控視角的運維體系架構,打造了一個多維度可視化的綜合運維監控管理平臺。系統以故障提前預警、問題快速定位為核心。切實保障信息系統的安全穩定運行。


分享到:


相關文章: