1969 — Unix 誕生#
案件摘要#
1969 年,當 Bell Labs 退出 Multics 計畫後,Ken Thompson 用閒暇時間在廢棄的 PDP-7 上寫出了 Unix——一個小到一人可維護、卻改變了整個電腦世界的作業系統。它的哲學(do one thing well、pipe、一切皆檔案)與可移植性,造就了今天 macOS、Android、Linux 的共同血統。
前因 -- 為什麼會有這個案子#
1964 年,MIT、Bell Labs 與 GE 合作啟動 Multics(Multiplexed Information and Computing Service)計畫,目標是造一台「像電力公司一樣」提供所有人共用計算資源的超大分時系統。願景宏偉,但工程上越走越沉重:
- 系統目標不斷膨脹,寫了數年仍無法達到可用的穩定度
- 代價高昂:只支援 GE 645 一種機器,無可移植性可言
- 1969 年,Bell Labs 經費吃緊,決定退出 Multics
退出後,Bell Labs 的研究員(Thompson、Ritchie、McIlroy 等)失去了好用的計算環境——他們在 Multics 上養成的互動式分時工作習慣,面對 IBM 7094 批次卡片投遞完全無法忍受。
破案的第一個線索來自一個遊戲:Thompson 在 Multics 上寫了一個太空旅行模擬遊戲 Space Travel,移植到 7094 上每玩一次要燒 $75 的機時。他發現角落裡一台閒置的 PDP-7(1964 年出品、18-bit、記憶體僅 8K words),決定把遊戲搬上去。為了讓遊戲有檔案系統,他順手用 PDP-7 組合語言寫了一個小型檔案系統,然後是程序載入器、shell、編輯器——一個作業系統就在一個人的閒暇時間裡誕生了。
同事 Brian Kernighan 開玩笑地把這個系統命名為 Unics(UNiplexed Information and Computing Service,Multics 的「單工版」反諷),後來拼法演化為 Unix。1970 年,團隊爭取到一台 PDP-11,Unix 正式在 Bell Labs 內生根。
線索與推理 -- 數學式、程式、理論#
1. Multics 的教訓:化繁為簡的設計公理#
Multics 的失敗給了 Unix 一個反面教材,團隊把它昇華為設計公理:
- 小即是美:單一功能、單一程式,而非無所不包的巨系統
- 一人可懂:整個系統的複雜度必須控制在一顆頭腦能容納的範圍
McIlroy 後來把這個哲學總結為:
「Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.」
若以數學眼光看,Unix 哲學就是函數組合(function composition)的工程化:與其造一個萬能函數 \(F\) ,不如造一群小函數 \(f_1, f_2, \dots, f_n\) ,讓複雜任務表示為它們的組合:
Multics 想造 \(F\) (一個龐大而全知的系統),Unix 選擇了 \(f_i\) 的組合。歷史判決:組合勝出。
2. Pipe:串流組合的發明#
Unix 哲學最有力的支撐是 McIlroy 提出、Thompson 在 1973 年實作的管線(pipe)。管線讓一個程式的標準輸出(stdout)直接接上另一個程式的標準輸入(stdin):
grep "error" log.txt | sort | uniq -c | sort -rn | head -5
這行 shell 命令把五個各只做一件事的程式串成一個資料分析流水線,等價於數學上的:
管線的深遠之處在於它強迫所有程式採用統一介面:文字流(text stream)。文字流是惰性、可串接、可增長的抽象——不像二進位格式需要預先定義 schema。用現代語言說,pipe 是惰性求值序列(lazy sequence)的最早工程實現;Python 的生成器串接是它的直系後裔:
import re
lines = (l for l in open('log.txt')) # cat
hits = (l for l in lines if 'error' in l) # grep
from collections import Counter
count = Counter(re.sub(r'\d+', 'N', h).strip() for h in hits) # uniq -c
for k, v in count.most_common(5): # sort -rn | head
print(v, k)
3. 一切皆檔案#
Unix 的第三大發明是檔案系統的統一抽象:磁碟、終端機、印表機、後來的行程間通訊(pipe、socket),全部以「檔案」的介面呈現。檔案就是一個可讀寫的位元組序列,存取介面只有三個基本操作:
因此 read(fd, buf, n) 對磁碟檔案和對終端機是一樣的呼叫。這個抽象讓工具程式不需要知道資料從哪裡來、到哪裡去——輸入可以是磁碟、pipe 或鍵盤。這是「依賴注入」思想在作業系統層的原始形式。
4. Portability 與 C 重寫#
1972 年前,Unix 完全以 PDP-11 組合語言寫成,綁死在一種機器上——正是 Multics 的老毛病。Thompson 與 Ritchie 的解法是:用 1972 年新發明的 C 語言重寫 Unix(1973 年完成),把 Unix 從「某台機器的 OS」變成「一種架構無關的 OS」。到了 1970 年代末,把 Unix 移植到新機器的成本從「重寫數年」降為「修正數週」。可移植性讓 Unix 走出 Bell Labs、走進大學、走向全世界。
結案 -- 後果與影響#
- 譜系分化:1970 年代末 Unix 分為兩大譜系——AT&T 的 System V 與 UC Berkeley 的 BSD(Berkeley Software Distribution)。兩者競爭(「Unix 戰爭」)數十年,共同塑造了今天的 Unix 世界。
- macOS 的血統:macOS 的核心 Darwin 以 Mach + BSD 為基礎,是經認證的 UNIX(Apple 於 2007 年起通過 UNIX 03 認證)。你在 Mac 上用的終端機、shell、
grep、ssh,全是 Unix 血統。 - Android 的血統:Android 核心是 Linux kernel——Linux 是 1991 年 Linus Torvalds 受 Minix(Tanenbaum 用來教 Unix 哲學的教學版 Unix)啟發的作品。全球數十億支 Android 手機、數百萬台伺服器,血統都源自 1969 年那台 PDP-7。
- 開源文化的起點:BSD 與 Unix 社群的原始碼共享文化,直接孕育了自由軟體運動(1983)與開源運動(1998)。
- 哲學傳承:do one thing well 與 pipe 哲學影響了 Go(Unix 精神的現代重譯)、Plan 9、以及今日的雲端工具鏈(
kubectl | jq、Docker 的單一職責容器)。
關鍵人物與文獻#
- Ken Thompson:Unix 之父、B 語言作者、UTF-8 共同發明人、圖靈獎得主(1983,與 Ritchie 同獲);也 co-author 了 Go 語言。
- Dennis Ritchie:C 語言之父、Unix 共同創建者;Thompson 寫功能,Ritchie 讓它可移植。
- Doug McIlroy:pipe 概念的提出者,Unix 哲學的正式表述者。
- Brian Kernighan:Unix 命名者、《The C Programming Language》第一作者、AWK 共同作者。
- 文獻:Ritchie & Thompson, "The UNIX Time-Sharing System", CACM, 1974;McIlroy et al., Bell System Technical Journal, 1978;Eric Raymond, The Art of UNIX Programming(2003)。