Multics
戈登·M·布朗
这就是Unix的故事。然而,要全面了解Unix的演变,首先必须讲述Multics的故事。Unix诞生于贝尔实验室,源于Multics项目失败的尝试。Multics原本是当时最先进的分时计算机系统。1969年,贝尔实验室退出了Multics项目,但同时也带走了Multics项目中许多重要的理念,这些理念后来成为了Unix的基石。此外,贝尔实验室的发展重心从计算机转向其他领域,营造了一种充满创造力和独立思考的氛围,这对Unix的开发至关重要。Multics项目以及贝尔实验室退出Multics项目的决定,对Unix分时系统的形成产生了多方面的影响。
多路复用信息与计算服务(Multics)是分时系统的延续,其发展源于对更广泛计算资源的需求。美国高级研究计划署(ARPA)信息技术处理办公室主任JCR Licklider是这一理念的主要倡导者,他致力于更高效地将计算机与人类活动相结合。当时,信息技术处理办公室资助了许多计算机相关项目,例如麻省理工学院的MAC项目(Cambell-Kelly和Aspray,第214页)。MAC项目(全称为Multiple Access Computers,在Marvin Minsky的人工智能实验室中也被称为Man and Computer)由Robert M. Fano领导,其中包括兼容分时系统(CTSS)。CTSS是最早的分时系统之一,它是一个功能齐全的系统,最多可支持30个远程用户,也是MAC项目不可或缺的一部分。然而,到了1965年,MAC项目已经使CTSS不堪重负,麻省理工学院开始寻求第二代分时系统。这就是 Multics 项目,其目标是创建一个能够支持数百名用户的动态模块化系统。通用电气和贝尔电话实验室也加入了麻省理工学院的这项计划。通用电气此前曾为达特茅斯分时系统提供硬件,并为 Multics 项目提供了一台 635 型大型机(后来更名为 645 型)(Cambell-Kelly 和 Aspray,第 215 页)。另一方面,贝尔实验室则提供了大量的编程经验。作为一家公共事业公司,贝尔受到 56 号同意法令的约束,该法令实际上限制了其独立的计算项目,因此 Multics 项目对于贝尔的计算机人才来说是一个完美的平台,也是提升其软件编写能力的绝佳机会。这三个机构共同致力于创建一个能够为计算机作为一种公共事业树立新标准的系统。
Multics 的初衷并非仅仅是为了取代不堪重负的 CTSS,而是要超越分时计算的范畴,创建一个社区计算平台。为此,系统模块化设计至关重要,以便支持未来的发展和变化。为了便于维护并最大限度地提高代码的清晰度,PL/I 被选为编程语言。PL/I 编译器的开发外包给了 Digitek 公司(《Multics 历史》,第 3 页)。在等待编译器交付期间,Multics 的设计方案被写入了《Multics 系统程序员手册》(MSPM)(Corbato, FJ, Saltzer, JH 和 CTClingen,第 2 页)。这种严谨的规划方法体现了编程团队在构建系统时所秉持的严谨作风,也被认为是有效管理项目复杂性的必要手段。该系统旨在实现无故障的连续运行、便捷的远程终端访问以及选择性的信息共享。 Multics最重要的特性之一是顺应集成多任务处理的趋势,允许在同一操作系统下运行多个编程环境和不同的人机界面。Doug McIlroy强调,Multics的意义并不在于允许多人共享机器的计算周期:
正是因为它允许许多人同时处理同一个庞大的数据池,而这种数据共享带来的协同效应——能够快速查看他人的文件、传递信息等等——才是分时共享最大的优势。其他优势仅仅是经济上的,而数据共享则带来了一种截然不同的机器使用方式。
虽然这大大增加了 Multics 的复杂性,但也反映了人们对交互式系统的渴望,这种系统可以提高计算机作为通信工具的能力。
系统设计开发持续了一年,但PL/I编译器仍然没有出现。这归因于实现完整的PL/I语言的难度。Doug McIlroy和Bob Morris决定自行开发一个系统备份,他们使用EPL/I(早期PL/I)编写了一个编译器,该编译器能够生成EPL Bootstrap汇编语言的输出(Multics历史,第3页)。然而,这种方法不仅编译速度极慢,而且在可实现的功能方面也存在诸多限制。例如,McIlroy指出:“只有两条错误信息,语法错误和重复声明,以及一条警告信息,愚蠢的结构”(Peter Salus,第28页)。由于软件中各个逻辑执行路径的实际性能与预期性能之间存在巨大差异,导致设计迭代阶段出现意料之外的情况,这使得问题更加复杂。
因此,该项目开始落后于计划,威胁到剑桥项目(一个由ARPA资助的政治科学计算项目)提供的过渡性资金(Multics历史,第4页)。软件问题的严重程度很快引发了广泛担忧,早在1967年,人们就对Multics的未来产生了越来越多的疑虑。贝尔实验室当时的计算机科学研究主管萨姆·摩根也表达了他对Multics研究进展缓慢、浪费精力的担忧,他说:“人们越来越清楚地意识到,Multics就像是试图同时攀登太多的山峰。开发进度比预期要慢得多,用户们也对此怨声载道。”事实上,对于整个实验室的计算机社群来说,Multics未能及时交付任何可用系统这一点已变得越来越明显。
因此,贝尔实验室于1969年3月退出了该项目,只留下通用电气和麻省理工学院尽力挽救该系统。据伯克·塔格(Berk Tague)所述,是比尔·贝克(Bill Baker)做出了终止该项目的决定,他说:“就像在越南一样,他(比尔·贝克)宣布胜利,然后退出了Multics项目。”麦克罗伊(McIlroy)也表达了类似的看法,他提到贝尔实验室“阁楼里堆放着价值一百万美元的设备,却只有三个人摆弄。很明显,我们拖累了计算机中心的预算。”Multics系统的突然终止对贝尔实验室的计算机发展方向以及Unix的诞生产生了重大影响。
大约就在这个时候,桑迪·弗雷泽来到了贝尔实验室。弗雷泽原本是一名航空工程师,此前一直在英国剑桥从事ATLAS分时系统方面的工作。后来他意识到,计算机的未来不在英国,而是在大西洋彼岸。他满怀希望地来到这里,希望能参与Multics项目的研发,却惊讶地发现该项目已被取消。他注意到贝尔实验室内部也有类似的反应:
很明显,对很多人来说,我们正经历着一场相当痛苦的变革。[例如],60年代末期是所有大学变革的时期。过去,计算机科学研究团体负责运营大学的计算中心。然而,随着预算的增长,这种模式很快变得越来越不切实际,[于是]各大学开始陆续将计算机的管理责任从计算中心转移到行政部门。Multics的退出就是这种情况。
随着 Multics 的消失,贝尔实验室的发展势头发生了决定性的转变,不再专注于计算机领域,因为管理层试图将动力转移到其他研究领域。
当时的一大特点是计算机科学人员流失到其他院系或研究机构,以及计算机科学项目缺乏空间和资金。事实上,为了防止 Multics 死灰复燃,校方甚至不鼓励校长们购买任何足以运行 Multics 的大型计算机。然而,Multics 项目的主要参与者(Ken Thompson、Dennis Ritchie、McIlroy 和 JF Ossanna)希望继续沿用 Multics 提供的公共计算环境。他们在 Unix 系统中找到了 Multics 的替代方案。
Unix 虽然未必是对 Multics 的回应,但它无疑代表了一种不同的分时解决方案。贝尔实验室的系统程序员 Ritchie 表示:“Multics 的消失,以及 Ken Thompson 一直想编写自己的操作系统,这两者结合起来,直接促成了 Unix 的诞生。” 他还解释了编程团队创建 Unix 的另一个原因:
我们不想失去我们所占据的舒适空间,因为当时没有类似的空间;即使是后来在通用电气操作系统下提供的分时服务也不存在。我们想要保留的不仅仅是一个良好的编程环境,而是一个可以围绕其形成互助精神的系统(丹尼斯·M·里奇,第1页)。
这种理念促成了一种简单而有效的系统设计,其核心是易用性和密切沟通。
此外,Multics 开发过程中形成的两个关键概念后来也成为了 Unix 的定义基础。这两个概念分别是:系统中不太重要的功能会引入更多复杂性;反之,算法最重要的属性是简洁性。Ritchie 向 Mahoney 解释了这一点,他阐述道:
Multics与Unix 发展之间的关系其实很有趣,也相当复杂。很多文化元素几乎被全盘照搬。这其中就包括一些重要的东西,比如层级文件系统和树状文件系统——顺便一提,这些在PDP-7上的第一个 Unix 版本中并没有出现。这正是整个过程如此复杂的原因之一。总之,像层级文件系统这样的概念,以及一些简单的操作选择,比如在输入时编辑行、删除字符等,都与我们当时使用的相同。我认为最重要的根本在于,人机交互的基本方式,也就是命令行——它本质上就是一个 shell 程序。事实上,“shell”这个名字就来源于Multics。很多极其重要的东西都被完全内化了,当然,这就是现状。很多东西都源自Multics。
正如后文将要讨论的,将 Multics 设计的诸多方面整合到 Unix 中,保留了 Unix 作为分时系统的强大功能。相比之下,Unix 系统的简洁性避免了 Multics 系统的许多负面影响,正如 Ritchie 在下文中所述:
至于其他技术细节,两者之间存在着巨大的差异。无论是人力、物力还是机器资源,规模都无法相提并论。我现在记不清Multics机器有多大了,当然,以今天的标准来看它并不算大,但第一台PDP-7处理器非常小巧。[Unix的设计内存]只有8KB,[而Multics运行的机器却有]68KB。因此,两者的复杂程度相差悬殊。很多差异都是由当时的条件造成的。但很多时候,这确实也与个人喜好有关。Multics在商业上失败的一个显而易见的原因就是它在某种程度上过度设计了。它包含的功能太多了。这也解释了为什么它花了那么长时间才步入正轨。它对资源消耗巨大,无论是机器资源还是生产所需的人力。
里奇的言论反映了Multics失败对贝尔实验室计算氛围的影响,并由此说明Unix的关键在于通过编写简洁、优秀的程序来避免这些问题。正如萨姆·摩根所暗示的那样,“如果你要求一群程序员开发操作系统,你得到的就是Multics。如果你让他们自由发挥,发挥想象力,像Unix这样的系统就会从他们的创造力中诞生。”正如接下来要讨论的,Unix文件系统的发展显然源于这种理念。
开端
迈克尔·埃雷卡特和卡梅伦·琼斯
共享文件
Unix 的开发最初并非着手开发操作系统。实际上,贝尔实验室退出 Multics 项目后,一小群计算机科学家失去了工作岗位,于是他们开始着手创建一个可以在工作组内高效共享的文件系统。操作系统只不过是出于测试这个文件系统的需要而产生的后续产物。
当贝尔实验室退出Multics项目时,肯·汤普森和他的小组正在为该项目开发文件系统,但由于几个技术难题变得过于复杂而无法解决,这个文件系统“最终未能真正建成”。他们的目标是“开发出顺序读写调用,最终实现从页面中顺序读取数据”,但一种名为“分页”的技术却出现了问题。分页技术原本旨在简化磁盘文件的读写过程,但最终被放弃了。
Unix 文件系统几乎完全基于失败的 Multics 项目的文件系统。其理念是为每个用户显式地使用独立的文件系统进行文件共享,从而避免文件表被锁定。正如 Thompson 所概述的,该文件系统的主要思想是“使用户一和用户二的数据操作活动区域分离,这样实际上就不会锁定公共表。除非他们共享文件,否则他们不会访问任何公共内容。力求保持对磁盘的高效访问。实际上,要以某种方式交错访问。” 显然,Multics 的主要目标——普遍访问无限的中央计算能力——在 Thompson、Canaday 和 Ritchie 为 Unix 开发文件系统的过程中得到了很大程度的延续。Stu Feldman 指出,Project MAC 和 Multics 共同影响了文件系统的发展:
MAC 项目有一个相当怪异的、并非真正意义上的树状结构的两层文件系统,每个名称都对应一个双补码标识符。Multics 的文件系统则非常复杂,与 MAC 项目截然相反,它拥有极其混乱的目录结构……可以在其中表示数量惊人的重要信息。极其复杂的访问控制,极其复杂的链接控制……各种各样的奇妙功能。所有这些奇妙的功能最终导致系统陷入困境……万物皆有周期。许多类似的理念后来以其他形式再次出现。因此,从某种意义上说,Unix 文件系统正是对上述两种方案的回应。它具有灵活性,拥有 Multics 那种树状结构的灵活性。但它的实现方式却非常糟糕,那就是将文件空间视为扁平的。
肯·汤普森是文件系统创建过程中参与度最高的人,他负责所有的编码和调试工作,同时还在白板上与其他人交流想法。项目经理道格·麦克罗伊谈到了Multics和Unix之间的过渡,他说:
汤普森、里奇,还有在我部门实习了一年的鲁德·卡纳迪,他们当时正在讨论:“我们怎样才能用更简洁的方式实现这个功能呢?”于是,他们花了许多个下午在走廊对面的黑板前工作,设计着……后来成为Unix文件系统的东西。“如果我们要做一个文件系统,它会是什么样子呢?”
这个问题的关键在于文件系统必须开放。团队的需求决定了每个用户都必须能够访问其他用户的文件,因此Unix系统必须极其开放。这种开放性甚至体现在密码存储上,密码存储完全没有隐藏,只是进行了加密。任何用户都可以看到所有加密的密码,但每秒只能测试一种解决方案,这使得入侵系统极其耗时。文件系统开放性的另一个例子是省略了记录(receiver)格式,这一决定受到了各方的强烈批评。记录格式的专有性使得不使用相同记录格式的用户无法访问它们,这对于团队来说是不可接受的。汤普森说:“我做演讲时,总会有人问,为什么不用记录格式,所以我会准备一些额外的幻灯片,因为我知道肯定会有人问这个问题。”他会向听众演示不兼容的记录类型可能出现的问题,以此来证明他的观点。
在设计过程中,汤普森明确表示,Multics 项目中的文件系统有一些他希望实现但最终未能实现的功能。一个主要的例子是“将文件和设备视为同等对待……使用相同的读取调用”。这意味着终端将以与大型机相同的格式输入和输出数据,从而使不同计算机上的用户拥有公平的竞争环境。“在那个年代,终端和文件系统本身通常使用不同的调用方式……混淆它们并重定向 I/O 在当时是行不通的。”设备标准输入输出的概念最终以管道的形式被引入 Unix 系统。管道允许用户和程序员通过在两个函数之间添加一条竖线“|”将一个函数的输出传递给另一个函数。管道是 Unix 最显著的特性之一,我们将在后续章节中详细介绍。汤普森认为“大家都把[标准 I/O]看作是一个简洁的概念,也是应该做的事情,但不知何故,它就是没有被采用。”
当文件系统最终不再局限于抽象的开发和修改,而必须在实际硬件上实现和测试时,汤普森阐述了他对文件系统应有形态的设想:“首先是 I 列表,它定义了系统上的所有文件;然后其中一些文件是目录,目录只包含名称和 I 编号。其中没有任何东西限制它必须是一个树状结构。所以它实际上根本不是层级结构。” 正如终端和大型机一样,目录也只是附加了索引的文件。然而,最初实现中固有的缺陷也逐渐显现出来:
当[团队]开始编写文件系统检查程序之类的东西,以及锁定混乱的目录结构和查找分离的文件时,你会发现有些东西一旦丢失就再也找不回来了。这些问题几乎无法克服,因此在下一个版本中,我们强制采用了一种比之前更强大的拓扑结构。
这种新的拓扑结构虽然限制略多,但仍然大致平等地对待文件和目录,符合该项目的精神。
在解决了单个用户是否能够有效使用该系统的问题之后,现在是时候测试该系统在预期使用情况下的性能了,即多个用户同时连接并对磁盘进行读写调用。
要运行文件系统,你必须创建文件、删除文件、重新合并文件,才能测试它的性能。为此,你需要一个脚本来描述你希望文件系统上的各种流量。我们当时用的脚本是纸带,上面写着读取文件、读取文件、写入文件之类的操作。你把脚本运行在纸带上,它会稍微震动一下磁盘……你根本不知道发生了什么。你既看不到,也无能为力。
由于无法有效监控这些测试中文件系统的成功和失败情况,该小组
我们在文件系统上构建了一些工具……用纸带将这些工具加载到文件系统中,然后我们从文件系统中运行这些工具……并对这些工具进行输入……以此来操控文件系统,使其发生我们想要的各种变化,从而测量它的运行方式和反应。因此,(这个文件系统)本身可能只运行了一两天,之后我们就开始开发加载它所需的工具。
正是通过这种方式,加上系统工具的加入,分层文件系统的概念成为了更宏大的基础。
此时,团队内部开始萌生一种想法:他们正在开发的东西不仅仅是某个大型操作系统的文件系统。虽然大多数文件命令仍然是纯粹的系统命令(“系统读取调用实际上就是文件系统的读取调用,而且是同步的”),但随后“进行了一次快速重写,承认它是一个操作系统,并且拥有一个可以通过内核接口访问的用户界面”。至此,它才正式被称为操作系统。值得注意的是,Unix 团队的其他成员对这个早期文件系统的看法与它的创建者 Ken Thompson 截然不同。Stu Feldman 声称:“Thompson 当时正在编写《太空大战》(Space Wars),他厌倦了得不到任何支持。所以,他自己开发了一些东西。”这种为自身利益而开发工具,并根据团队需求进行调整的理念,在 Thompson 的访谈中也得到了体现,他在访谈中解释了自己开发 Unix 的动机。 “我当时更关注自己。只是出于自私的想法,想创造一个适合自己的工作环境。” 丹尼斯·里奇也参与了文件系统的创建,只是贡献较小,他进一步证实了这种说法:
我认为(文件系统研究)基本上是 Ken 想开发一套属于他自己的系统的想法的一部分。所以我不太清楚具体是什么契机激发了这个想法……然后他和 Rudd Canaday 开始在黑板上(也可能是白板)画图,描绘这个拟议系统的结构,它在很多方面都是 Unix 的前身……大部分想法都来自 Ken。
无论Unix的初衷是什么,它似乎都展现出一种超乎所有人预料的潜力。而要继续沿着这条道路前进,它需要用一种可靠的语言编写出可靠的代码。
从B到C的语言
选择一种编程语言来编写 Unix 系统,其对 Unix 的塑造作用几乎与分层文件系统的开发不相上下,甚至更为重要。起初,肯·汤普森认为,Unix 必须拥有 Fortran 编译器才能被视为一个“严肃的系统”。然而,在着手编写 Fortran 语法之后,“他花了一天左右的时间才意识到,我们根本不需要 Fortran 编译器。” Unix 团队知道他们仍然需要一种高级语言,但 Multics 中使用的 PL/1 语言过于高级。因此,汤普森创建了一种新的、非常简单的语言,称为 B 语言。
当时,汤普森和里奇都接触过一种刚刚从麻省理工学院诞生的新语言——BCPL,并被它深深吸引。可惜的是,BCPL 体积太大,无法在 4K Unix 机器上运行,于是汤普森编写了 B 语言。B 语言与 BCPL 几乎完全相同,但它是一个解释器,而不是编译器。B 语言的运行分为两步:第一步是将代码转换成中间语言,第二步是解释这个中间语言。里奇为 B 语言编写了一个编译器,该编译器基于中间语言运行。一些系统工具和实用程序是用 B 语言编写的,但操作系统本身从未用 B 语言编写。B 语言本质上与 BCPL 相同;从语义上讲,两者完全一致。然而,从语法上看,它类似于后来的 C 语言,尽管它缺少类型系统。
汤普森设想B语言应该非常简洁、清晰且易于移植。“它是用一种独立的语言编写的。这就是它如此易于移植的原因。因为你只需把它导入进去,就能很快上手。”汤普森致力于打造可移植的Unix系统,而创建一种易于移植的语言正是实现这一目标的关键所在。
B 是一种面向字的语言,它运行在面向字的机器 PDP-7 上。然而,当它被移植到新的 PDP-11 上时,解释器遇到了一些问题。由于 PDP-11 是面向字节的,机器和语言并不兼容;特别是,B 和 BCPL 都有指针的概念,指针是存储单元的名称,并且指向单一大小的对象,而 PDP-11 的对象大小各不相同。此外,由于 B 是一种解释器,它的速度注定会很慢,因此 Unix 团队决定需要一种更好的系统语言,这促使 Ritchie 开始开发 C 语言,C 语言的开发分两个阶段进行。
Ritchie 首先在 B 语言中添加了一个类型结构,不久后便为其编写了一个编译器,这标志着第一阶段的开始。语言发生变化后,“它被命名为 NB,即 New B 的缩写……[并且]它同时也是一个解释器。” 为了编写 C 编译器,Ritchie 以 B 编译器为基础,并“将其与新的类型结构合并到 C 编译器中”。
编译器的基本构造,也就是编译器的协同生成器,是基于我从印第安山实验室的某人那里听到的一个想法——我实际上从未找到并阅读过这篇论文,但我听人解释了其中的想法,因此 NB 的协同生成器……是基于这篇博士论文。
基本上,C 最终包含了 B:“C 中的一些时代错乱之处,现在已经消失了,或者至少还没有消失,只是因为没有发表,以至于没有人知道它们的存在,这些就是 B。”
“第二阶段进展较慢;虽然所有事情都在短短几年内完成,但感觉上确实慢了一些,这源于……第一次重写Unix的尝试。” 1972年夏天,汤普森着手了这个项目,但最终放弃了。“也许是因为他厌倦了,或者其他什么原因,但主要有两个问题。一是他无法弄清楚如何……在进程间切换控制权。二是他难以处理的问题——在我看来,这更重要——是构建合适的数据结构。” 最初,C语言没有数据结构,因此创建各种类型的表“非常痛苦”;当时找到的一种解决方法充其量也只能说是笨拙。“正是这些因素导致肯在那年夏天放弃了这个项目。”
在接下来的一年里,里奇为 C 语言添加了结构体,并改进了编译器,使其代码更加完善。“因此,在接下来的那个夏天,我们集中精力,用 C 语言重写了整个操作系统。这项工作相当成功。我们花了 1973 年的整个冬天才完成。而且没有遇到什么真正的难题。”
此后,C语言迅速发展。它成功的部分原因在于它与Unix的紧密联系。随着Unix的普及,C语言也随之发展:“它就这样被带动起来了。”它流行的另一个原因是,许多与机器相关的特性对C程序来说是可见的,而且只要稍加注意,就能实现可移植性。“关键在于了解哪些东西可以依赖,哪些东西不应该依赖。我想,它成功的唯一真正原因在于,之前有很多人用C语言写作,通常是写散文,现在他们也能用C语言写作了。他们的程序很可能因此变得更好。”
在 Unix 成为广泛使用的系统之前,许多有趣的工具正在被开发出来,因此人们努力让其他人也能使用这些工具。“最好的方法是在其他机器上安装 C 编译器。”然而,Unix 小组在将各种 Unix 工具移植到 IBM、GE 或 Honeywell 系统时遇到的真正困难并非源于底层机器架构的差异(尽管 C 语言使得这种差异显而易见),而是源于操作系统本身的差异:“如何进行 I/O 操作?如何编写所谓的可移植库?保持这些程序的可移植性存在诸多问题。这与程序本身无关,而与程序和系统其他部分的交互密切相关。”解决方案是:与其浪费时间在与操作系统作斗争的同时试图使单个程序可移植,不如使操作系统本身也具有可移植性。早在小组还在使用 PDP-7 时,Thompson 就提议编写……
在B中,他设想了一个非常简单的操作系统,它将非常非常便于携带。它可以在当时市面上各种微型计算机上运行。它并不追求宏大,而是希望能够广泛分发……这个想法只是有一天突然冒出来的,我想他根本没花任何时间去开发它。尽管这个想法并没有立即或直接地产生任何成果,但这却是Unix可移植性,尤其是系统可移植性的最初萌芽。
Unix小组早期的工作重点既在于文件系统的开发,也在于C语言带来的可移植性。这为操作系统的进一步发展奠定了基础,为小组的运作搭建了基本框架,并为Unix理念的实现铺平了道路。但是,在此之前,他们首先需要找到一台属于自己的计算机。
寻找机器
达丽丝·王和杰克·克纳
1969年3月Multics项目终止后,几乎所有部门都被禁止购买足以继续Multics研究的计算机。萨姆·摩根于1967年成为贝尔实验室计算机科学研究部门的负责人,当时Multics项目正处于进行中。他亲历了Multics项目的终止和Unix的诞生。
我们正式宣布停止这项工作,不再投入任何精力到 Multics 项目上,我们彻底退出了。我认为必须这样做,因为……除非明确声明不再继续某个项目,否则总会有人继续做下去。这就是科研的常态。大家每天都在做自己的事情。所以,我们明确宣布这项工作已经结束……它只是在消耗精力,毫无进展,也没有任何希望最终变成对用户有用的产品。
导致AT&T决定不再购买任何足以运行Multics的计算机的因素有很多。正如萨姆·摩根回忆的那样,1969年年中,贝尔实验室所有技术部门都取消了服务计算:
……贝尔实验室所有地点的服务计算部门……合并成一个由菲尔·泰耶领导的单一部门……所有计算中心都实行统一管理,在一年半的时间里,我同时担任默里山和惠帕尼的服务计算主管以及计算机科学研究主管。……对于一个研究机构来说,还要管理一个稳定的计算中心,这实在是不现实的。所以,成立一个独立的计算服务机构早就应该了。[这个独立的计算机构]于1969年中期成立。
我认为这是推动小型计算机操作系统(即Unix)开发的另一个重要因素,而Unix正是计算机科学研究领域的一个重要组成部分。因为一旦计算中心的机器脱离了研究部门的管辖,我们在研究部门就有了自己的机器,而管理层又不愿意购买大型的DEC PDP-10计算机,所以我们只能在小型计算机上进行开发。这也进一步推动了汤普森和里奇朝着Unix方向发展。总之,这就是事情的大致经过。
许多科学家不理解,或者不愿理解,AT&T已经退出计算机行业。汤普森尤其回忆说:“当时并没有明确的政策说我们不会重返计算机业务。”
汤普森和里奇开始着手开发类似Multics的文件系统,因为他们和大多数科学家一样,都喜欢使用Multics,并且希望继续进行研究。萨姆·摩根认为,科学家们喜欢Multics是因为“Multics很有趣。你可以用它开发软件,可以做各种各样的事情。只是它……不太划算。”由于Unix的开发者们喜欢Multics提供的环境,因此Unix在开发过程中“最终成为一个更简单、更经济的环境,它为用户提供了……同样的沙盒体验”,可谓两全其美。汤普森和里奇决心找到一台计算机来继续进行类似Multics的研究。他们找到的是一台老旧的DEC PDP-7,这是当时唯一可用的系统。它的内存非常有限,但至少他们可以实现一个文件系统。
这台PDP-7是专门为比尔·明基(Bill Minkey)的复杂图形工作而改装的。它属于13号部门,负责人是约瑟夫·康登(Joseph Condon),一位研究电流的电气工程师。康登的团队当时并没有使用这台电脑,肯·汤普森(Ken Thompson)和丹尼斯·里奇(Dennis Ritchie)就拿它玩。他们甚至还编写了一款著名的电脑游戏——《太空旅行》(Space Travel)。萨姆·摩根(Sam Morgan)指出:“肯·汤普森当时正在寻找一款可以替代Multics的电脑,他玩了一段时间的太空战争游戏。”
当被问及汤普森和里奇是如何使用不属于他们部门的电脑时,康登说:“我不知道。”事实上,在汤普森和里奇开始借用这台PDP-7电脑后,康登就成为了拥有这台电脑的部门的负责人。汤普森解释了事情的经过:
那台机器是另一个部门的,一旦出了故障,维护责任就很难分清,而我们部门又不愿意出钱,所以我们自己也没办法维护。没钱……他们就是不想让我们做这件事。……拥有那台机器的部门……想把它扔掉,但我们想把它留在他们的场地里,自己维护。情况很棘手,而且一直持续着。后来,当这些机器明显快要报废的时候,我们……试图把它们正式归我们所有,但失败了,我们的经理不愿意免费接收这些机器,你知道,他们不想承担场地费用。
当汤普森意识到PDP-7的性能不足以实现一个能够提供Multics部分优势的文件系统时,他最初编写了一个极其简陋的文件系统。之后,这个文件系统被移植到PDP-10上。利用PDP-10增强的性能,汤普森和其他人逐步添加工具来帮助他们监控文件系统的运行情况。汤普森分别用一个月的时间来开发shell、编辑器、汇编器和其他软件工具。当被问及何时意识到一个新的操作系统正在诞生时,汤普森回答说:
……在 1969 年夏天,它被完全重写成一个看起来像操作系统的形式,带有一些当时为人所知的工具,比如汇编器、编辑器和 shell——即使没有自我维护,也几乎就要自我维护,彻底切断与 GECOS 的连接。
正是在这一点上,UNIX 的诞生成为了现实。该操作系统用汇编语言编写完成后,被命名为 UNIX,这是对 Multics 的一种巧妙组合;MULTI 代表多,UNI 代表一。
PDP-7 的文件系统是用汇编语言编写的。如上所述,汤普森意识到,操作系统要想真正有用,就必须用高级编程语言编写,这样才能移植到任何系统上。汤普森最初尝试编写 Fortran 编译器,但后来改变了主意,创建了一种非常简单的语言,称为 B 语言。里奇改进了 B 语言,并将其更名为 C 语言。UNIX 就是用 C 语言编写的,因此可以移植到任何计算机上。
由于Unix具有可移植性,现在可以在更大的机器上进行试验。唯一的问题是找到一台与Multics大小相近的机器,以及一位愿意购买它的部门主管。汤普森能够回忆起整个过程。
……我们开始着手准备一系列购置新机器的方案……事情的经过是这样的:我们会把这些方案拿来,进行各种调研,联系供应商,浪费大家的时间,然后把方案提交上去,提交给管理层,让他们考虑很长时间,但他们总是莫名其妙地拒绝,你知道,他们再也不会为了真正的(不明原因的)计算需求而拒绝了。我们进行了好几轮这样的努力,试图找到供应商和机器,并完成这项工作。大部分工作都是我和奥桑纳以及那些喜欢从中作梗的人做的。最终,我们找到了一台PDP-11,实际上它当时还没有正式发布,但已经接近发布了。
奥萨纳和我一起拟定了一份购买PDP-11的提案,用于进行文本处理(具体内容不明确)和文档准备方面的研究。这是我们提出的几个具体目标中的第一个。其他目标包括……我们想玩玩电脑和操作系统,但这些目标比较笼统。我们的管理层考虑了一番,然后再次否决了这项提案。与此同时,我们上下级沟通后,一个兄弟部门——122心理学研究部门——过来表示“我们会从我们部门拨款”,这让我们的管理层颜面尽失。他们最终购买了这台电脑,并把它给了我们。他们当时很有远见,也很有灵感,而我们的管理层却没有……我们的管理层仍然深受Multics时代遗留问题的困扰。
最终,Unix 机器提案小组的四名成员之一,也是唯一一个来自其他部门的成员李·麦克马洪,说服了自己的部门主管资助购买一台机器。
与此同时,乔·奥桑纳说服了贝尔实验室专利局,Unix 作为文本处理系统是一项值得投资的方案。Unix 最初在贝尔实验室专利局使用,但到 1972 年,贝尔实验室的许多非研究机构也开始使用 Unix 进行软件开发。摩根回忆起文本处理在 Unix 创立过程中所起的重要作用。
[太空旅行]很有趣,但Unix文件系统的第一个真正应用是文本处理系统。这可以说是文件系统工作与人们长期以来一直感兴趣的文本处理工作的融合……
人们对文本编辑和格式化很感兴趣,而这在小型计算机上就能实现……前提是操作系统能够轻松处理文件,并且支持时间共享……这样人们就可以访问和使用彼此的文件。Unix 文件系统与文本编辑和格式化工作就这样结合在了一起……
实验室原本打算购买一台机器来运行[文本处理系统]。当初有人提出要购买一台机器用于文本处理时,因为采购订单需要我签字,所以这个提议就摆在了我面前。
虽然摩根事后承认文本处理的优点,但他最初拒绝这项技术时是这样辩解的:
[T]事情的经过并非是摩根的两个MTS成员被摩根赶出办公室(我在这里夸张了,但他们确实是被赶出了摩根的办公室),然后跑到马修那里说:“摩根不爱我们,你能帮帮我们吗?”他们是通过麦克马洪的主管进来的……最初向我提出这个提议的是奥桑纳、汤普森和麦克马洪,他们当时正在一起工作。
摩根承认他低估了这些提案,但作为部门主管,他的职责是依靠他所了解的东西,而他对文本处理了解甚少。
当时我并不理解Unix文件系统的创新之处,我们过去也做过文本处理方面的工作,但我并不认为我们取得了任何重大的研究进展。听起来好像大家只是想提供某种打字服务之类的东西。所以,第一次有人提议购买一台,我猜是PDP1120,我拒绝了……就像我之前说的,汤普森和他的团队第一次提出要买电脑时,他们想要一台DEC PDP10,但被拒绝了。那台电脑实在太大了,而且在Multics项目刚结束之后,你不可能马上就去研究一台大型电脑的操作系统。第二次他们提出要PDP-1120,我说:“我还没被说服,我想看看你们打算用这个文本处理系统做些什么。”
总之,他的哲学思想走的是一条较为宽松的道路。
我没有强迫他们,但也没有在他们的订单上签字。他们找到了其他人,另一位导演来签订单。第三次他们来的时候,想要11/45的合约,而那时他们已经有了一个完全合情合理、站得住脚的故事。所以,他们得到了有选择性的热情,但力度不大,时间也不紧迫。如果作品真的好,自然会证明一切。
摩根接受这些提议的一大难题在于如何应对他自己的管理层以及贝尔实验室高层的官僚作风。
嗯,我想我当时在区分信号和噪声方面遇到了一些困难。我很清楚,我的上司不会批准购买一台大型计算机来支持我秘密继续进行Multics项目。而且,我想我愿意等最初的反对声平息下来,并且我认为,如果文本处理工作中真的包含研究成分,那么它迟早会显现出来。事实也的确如此。
作为一名经理,摩根必须遵守管理规则。
这里的管理原则是:聘用优秀人才,让他们熟悉环境,给他们大致指明方向,并给予他们充分的自由。但这并不意味着一定要满足他们所有的薪资要求……你要对他们的工作给予有选择性的鼓励。如果你错误地打击或忽视了某个后来被证明是好的想法,如果它确实很有潜力,它终究会再次出现……
对摩根来说,他的决定以及该决定的后果都是自然而然的过程,没有什么可后悔的。
我从未在哪个组织里拥有足够的资金、足够的招聘名额、足够的办公空间或土地来做我们想做的一切。所以,总会有一些阻力。就从Multics过渡到Unix而言,Multics的资源必须被彻底切断。我的意思是,这是管理层的决定,他们决定切断Multics的资源。切断资源的一部分措施是不再立即购买能够继续运行的硬件。事后看来,Thompson、Ritchie和其他人确实通过自身的努力,以及寻找愿意购买硬件的主管,找到了一些可以继续使用的机器。后来,当研究领域的所有人都清楚意识到Unix将会走向未来并需要得到支持时,他们已经拥有了所需机器。他们只是去找了三人组中另一位主管。我认为这并没有什么不妥或不合理之处。
事情最终这样发展是有合理原因的。
马克斯·马修斯本来就喜欢收集小型计算机,而且当时他的资金可能比我充裕。我们公司有一定的预算限制。总之,我觉得这件事没什么不妥,也没觉得有人在批评我的判断。或许马克斯更有能力支持这台机器,或者其他什么原因,我也不清楚。但无论如何,我觉得这没什么不寻常的。现在回想起来,麦克马洪曾长期向我汇报工作。这件事发生后不久,他就从马克斯的部门调到了我的部门。但当时他是马克斯·马修斯的部门主管。所以他也加入了其他同事的行列,于是马克斯买下了第一台计算机。
但这并没有什么特别之处。如果一个中心的同事跑去问另一个主管“你能支持这笔投资吗?”,那才更不寻常。那样的话,我确信马克斯会来找我说:“你看,你们有两个人来问我能不能给他们买台电脑。如果要买电脑,你应该买。咱们讨论一下到底该不该买。” 事情之所以没这么发展,是因为马克斯的一个部门主管也牵涉其中。
在摩根看来,马修斯所在的部门比他自己的部门更适合为新机器的研发提供资金。
有人告诉我:“你看,马克斯·马修斯可以支持这个项目。”他是另一位导演。他为什么能支持呢?因为他对文本处理很感兴趣。他当时在做……他研究的是行为科学和心理学,他手下有人在做文本处理方面的工作,事实上,其中一位研究人员就提出了11/20的方案,但我拒绝了。
尽管困难重重,寻找合适机器的过程最终还是取得了成功。汤普森和他的Unix程序员同事们最终虽然找到了PDP-11/45,但PDP-7——这台机器体积太小——在Unix的发展过程中却发挥了至关重要的作用。如果没有PDP-7,历史或许会改写。
构建 Unix
杰森·奥根鲍、乔纳森·杰瑟普、尼古拉斯·斯皮彻
当团队拥有了自己的计算机后,成员们开始阐述他们根据使用 Multics 的经验所设想的系统和计算方式。表面上是为了支持他们购买这台计算机所要开发的文本处理系统,他们开始构建一系列软件工具,这些工具后来成为了 Unix 计算方法的标志。这些工具旨在促进和简化交互式编程,它们构成了一套“工作台”的基础,使 Unix 成为贝尔实验室的通用生产环境。在此过程中,Unix 本身也变成了一个工具箱,而不仅仅是一个操作系统。这个工具箱的核心是管道(pipes),这是一种系统进程,它允许将例程按顺序链接起来,一个例程的输出作为其后续例程的输入。麦克罗伊和克尼根都认为,管道创造了工具的概念。因此,软件工具的故事必须从管道的诞生开始。
作为一种比喻,管道强调了工具作为过滤器(或者更准确地说,作为转换器)的概念,它将输入符号序列转换为输出符号序列。这一概念与计算机研究领域的理论家们(尤其是 Al Aho)的研究方向非常契合。因此,许多工具的概念结构都体现了自动机理论、形式语言理论和算法理论的最新成果。这种与理论的紧密联系也成为了 Unix 计算方法或 Unix 精神的另一个特征。
Unix 的初衷是重现贝尔实验室 Multics 项目参与者们印象深刻的那种共享计算环境。在 Unix 工具箱逐渐成型的几年里,它的创建者们不仅共享一台计算机系统,还共享一间阁楼小屋。对他们而言,物理上的接近与文件和程序的共享同样重要。要理解 Unix 编程环境的经济性和高效性,就必须了解创造它的那个紧密团结的社区。
Unix的诞生并非仅仅,甚至主要也不仅仅是,一个文本处理和编程系统,它只是贝尔实验室、AT&T以及后来的学术界传播的载体。Unix的灵感和理念体现了一种计算机精神,一种关于计算机用途和使用方式的观点,一种关于计算机如何促进和增强人类社群的愿景。
接下来的章节将从管道的创建和Unix一些基本工具的开发开始。在了解了支撑这项工作的理论之后,我们将深入探讨Unix内部的协作模式。然后,我们将追溯Unix走向世界的主要路径,从最初作为文本处理系统而诞生的初衷,到Unix本身的传播。最后,我们将探讨伴随Unix软件而来的精神,正是这种精神使Unix超越了普通操作系统的范畴。
管道的起源
《Unix程序员手册》第一版出版于1971年11月3日;然而,管道的概念直到1973年2月出版的Unix第三版手册才被提及。尽管Unix在没有管道的情况下也能运行,但正是这种将多个程序连接起来的概念和符号,使Unix从一个基本的文件共享系统转变为一种全新的计算方式。管道的雏形早在其正式实现之前就以各种形式存在。事实上,麦克罗伊解释说,管道源于早期对宏的使用:
六十年代初,康威写了一篇关于协程的文章。大概在1963年,发表在《ACM通讯》上。我从1959年或1960年就开始研究宏了。如果你仔细想想宏,它们主要涉及数据流的切换。你正在接收输入,突然遇到一个宏调用,它说:“停止从这里接收输入,去从定义中接收。”在定义过程中,你会发现另一个宏调用。所以,宏……甚至早在1964年……我就在某个地方把宏处理器比作数据流的交换机。
阿霍回忆说,麦克罗伊对管道的概念进行了更深入的发展:
不过,我认为道格·麦克罗伊(Doug McIlroy)可能是管道翻译的作者。我记得他上世纪60年代在牛津大学的时候写过一篇未发表的论文……你应该读读这篇论文,因为它讲的是UNIX管道。道格有趣的地方之一在于,他有一些伟大而开创性的想法,但并非人人都知道。至于他是不是因为要求太高所以不发表……或者是什么原因?总之,这很了不起……
据汤普森称,管道的概念是 940 系统、CTSS 和 Multics 的思想相结合的结果。
当时有很多事情被讨论过,但并没有真正付诸实践。比如,文件和设备应该被同等对待,使用相同的读取调用。通常情况下,在那个年代,终端和文件系统本身会使用不同的调用。这些调用并不相同。混淆它们并重定向 I/O 在当时是行不通的。所以,我觉得……大家都认为这是一个很清晰的概念,也是应该做的,但不知为何,它就是没有被采纳。
里奇更愿意承认早期系统对管道的贡献。在他看来,“管道只不过是一种特殊形式的协程。即使是它的实现方式也并非史无前例,尽管我们当时并不知情;达特茅斯分时系统的‘通信文件’几乎实现了与Unix管道相同的功能,尽管它们似乎没有得到充分利用。”
麦克罗伊、汤普森和派普斯
尽管管道的概念早在 1972 年之前就以某种形式存在,但正是麦克罗伊倡导在 Unix 系统中实现管道结构。从项目伊始,他就一直在寻求一种改进的输入/输出结构处理方法。“这显然是一个绝妙的思维模型,即一个进程的输出可以作为另一个进程的输入。”麦克罗伊进一步解释道:
所以,这个想法在我脑海里酝酿了很久……就在汤普森和里奇在黑板上画文件系统草图的同时,我也在黑板上画着如何进行数据处理,通过将级联进程连接起来,并寻找一种用于连接进程的前缀表示法语言……
这很大程度上是他坚持要求最终实施管道建设的结果。
据里奇所述,麦克罗伊后来在黑板上向Unix团队解释了管道的概念。然而,这并没有立即引起团队的热情。他们对管道的表示法以及单输入单输出的命令执行结构提出了异议。尽管如此,麦克罗伊最终还是成功说服汤普森将管道功能添加到Unix系统中。汤普森解释了实现麦克罗伊想法的难点:
道格一直跟我们谈论这个,一个关于将计算机以网格和阵列形式互连的概念,你知道,非常复杂,而且他的方案总是存在问题……我的意思是,他的想法根本无法实现,我们一直在努力帮他精简思路,剔除杂质,提炼出有用的东西。到底发生了什么,需要什么,哪些是真正的想法,哪些只是他的幻想……我们……在那段时间里一直在讨论,直到有一天晚上,灵感突然涌现,它们瞬间就被采纳了,我的意思是,它们其实非常简单。
麦克罗伊对事件的回忆略有不同:
从 1970 年到 1972 年,我时不时会说“不如做个类似的东西怎么样?”,然后我会提出一个又一个方案。直到有一天,我终于想出了一个 shell 语法,可以配合管道使用。肯说:“我来做。”他已经听腻了这些……这当然也是关键所在……那天真是太棒了,第二天也是如此。“我来做。”他并没有完全按照我提出的管道系统调用方案来做。他发明了一个稍微好一点的方案,最终又修改成了我们今天看到的版本。他确实用了我那笨拙的语法……
最初,管道使用的语法与重定向相同(< 和 >)。然而,这被证明是繁琐的,因为几种不同的组合都可以表示同一个命令。就在伦敦的一次演讲之前,汤普森决定用竖线替换麦克罗伊的语法,从而消除旧语法的歧义。正如克尼根回忆的那样,“我记得那荒谬的语法,那个‘>>’之类的语法,是别人想出来的,然后突然间竖线出现了,一切都豁然开朗了。”麦克罗伊曾将这种结构比作“花园水管”,它的美妙之处终于被人们所认可:数据可以轻松地从一个程序流向另一个程序。
回想起来,管道符号的表示法和语法与管道符号本身的概念同样重要;如果没有这种与重定向的进一步区分,管道符号可能不会如此成功。正如阿霍回忆的那样,管道符号的全部含义在此之后逐渐发展起来:
在 60 年代,我当时真的没意识到它的重要性。而且我觉得当时也没人意识到,因为……很多这类理念……很多这类工具之所以能成功,都是因为 Unix 提供的框架。你可以使用管道,将一个程序的输出作为输入传递给另一个程序。
克尼根解释了为什么管道是更优越的输入/输出方式:
并不是说你不能做那些事,因为我已经写过重定向了;它比管道早得多。虽然早得不算特别久,但确实早。这算是个比较老的想法了。它足以完成你现在用管道做的大部分事情;只是在表示法上远没有那么方便。我的意思是,这有点像用罗马数字而不是阿拉伯数字。并不是说你不能做算术,只是很麻烦。或许要难得多,因此在思维上……也更受限制。
管道技术远远超出了麦克罗伊最初创建新型 I/O 机制的目标;程序员们利用管道将一个程序的输出发送到另一个程序的输入。正如克尼根解释的那样:
那时,我开始编造一些非常巧妙的管道命令示例,比如运行命令,将输出收集到一个文件中,然后统计文件的字数,统计用户数量,接着说:“看看用管道把结果导入到字数统计器里,再用管道把结果导入到文件who里,这有多方便啊!”我开始展示一些以前从未想过的组合,但它们却如此简单,只需在键盘上输入就能每次都正确无误。我想,正是从那时起,我们开始有意识地思考工具的重要性,因为如果你事先设计好工具,让它们能够协同工作,你就可以把它们组合起来使用。who who grep
正是管道的概念促成了软件工具箱理念的发展。麦克罗伊在接受马奥尼采访时坚称,管道“不仅强化了,而且几乎创造了”工具箱。
软件工具
开发后来被称为软件工具箱的第一步,是确保所有程序都能从标准输入读取数据。麦克罗伊解释了这个问题及其解决方案:
在那之前,大多数程序都无法接收标准输入,因为当时并没有实际需求。它们都使用文件参数。grep一个文件参数,cat一个文件参数。汤普森意识到这不符合当时的程序设计思路,于是他连夜修改了所有这些程序。我不知道他是怎么做到的。第二天早上,我们迎来了一场“单行代码”的狂欢。每个人都写了一行单行代码。“看看这个,看看那个。”
克尼根举例说明:
于是,人们开始有意识地在程序中加入这样的理念:程序会从文件列表中读取数据,如果没有文件,则从标准输入读取,这样就可以在管道中使用。人们有意识地在程序中这样做,比如sort…Sort——一个无法在管道中运行的程序,因为所有输入都必须先被读取才能输出——但这没关系,因为你最终还是要在管道中使用它,对吧?你不在乎它是否会在管道中短暂堆积;它最终都会从另一端输出。就是这样,我们说:“嘿,让它们协同工作。然后它们就变成了工具。”管道的出现,以及grep,Ken几乎一夜之间开发出的——正如Doug所说的——一个典型的工具,或许在其他环境下你不会这样看待它。但在Unix环境中,它在某种程度上被视为基本工具。
grep事实上,它是最早可以被归类为软件工具的程序之一。正如麦克罗伊解释的那样,汤普森应麦克罗伊的要求设计了它:
一天下午,我问肯·汤普森能否将正则表达式识别器从编辑器中移除,并编写一个单遍程序来实现此功能。他答应了。第二天早上,我在邮件中收到一封邮件,宣布了一个名为“grep”的程序。它运行得非常出色。当我问肯这个古怪的名字是什么意思时,他说这显而易见。它代表了它所模拟的编辑器命令:g/re/p(全局正则表达式打印)。
……从最初的特殊用途开始,grep很快就成为了家喻户晓的词汇。(我差点在上面第一段写出这样一句话,这足以说明这个概念如今已经多么根深蒂固:“我以前会ed从grep字典里查单词。”)与其他任何程序相比,“grep”更能体现克尼根和普劳格在《软件工具》一书中提出并正式阐述的观点:编写只做一件事并把它做好,且尽可能少地预设输入语法的程序。
专门程序的概念随着eqn数学文本格式化程序的开发而得到进一步发展,该程序由 Kernighan 和 Cherry 开发。Kernighan 解释了该程序eqn的开发过程:
有个叫X的研究生,他开发了一个数学运算系统,但他对这个系统应该的样子有着非常独特的理解。它基本上就是函数调用。所以,虽然它可能有效,但a) 我想他并没有完成,b) 这个模型可能本身就有问题。我记得,他和洛琳达一起开发过,或者洛琳达在指导他,诸如此类。我看了之后心想:“这好像不对劲,肯定有更好的表达方式。” 我的意思是,我突然就想到了“就按你说的做”这种想法。我不知道这种想法从何而来,虽然我可以推测一下。我在普林斯顿读研究生的时候,曾在盲人录音中心待过相当长一段时间,大概两年吧。我读过一些计算机评论之类的东西,也零星地读过一些教科书,所以至少我习惯了大声说出数学公式。或许,那刺激了某些神经元。
eqn是一款重要的软件工具,因为根据 Kernighan 的说法,它是“第一个——位于格式化程序之上或之前,真正扩展了格式化程序功能的工具”。eqn它更进一步grep;它不仅是一个功能单一的小程序,而且如果没有通过管道与其他程序连接,它几乎没有任何用处。
eqn这些grep例子体现了麦克罗伊(McIlroy)所阐述的Unix工具箱理念:“编写只做一件事并把它做好的程序。编写能够协同工作的程序。编写能够处理文本流的程序,因为文本流是一种通用接口。”这一理念被写入了克尼根(Kernighan)和普劳格(Plauger)1976年出版的《软件工具》(Software Tools)一书中,并在《贝尔系统技术期刊》(The Bell Systems Technical Journal)的“前言”中再次重申,该期刊也介绍了管道(pipe)。到20世纪70年代末这些著作出版时,软件工具已经成为Unix不可或缺的一部分,以至于人们很难想象没有它们的操作系统会是什么样子。正如克尼根所解释的那样:
人们进来后会问:“嗯,这不错,但是这个系统能做X吗?”(这里X指的就是某个功能),而对于所有这类问题,标准答案是:“不能,但很容易就能实现。”多年来,Unix一直以难学和功能不完善而闻名。难学意味着它的一套共享约定、运行方式的默认设置以及基本机制,都与其他系统截然不同。功能不完善意味着,由于它是作为程序开发环境而设计的,所以它不一定包含所有成品。但是,作为程序开发环境,它非常容易构建很多东西。它就像一个工具包。如果你想要一个新东西,你可以从工具包中取出各个部件,然后组装起来,比在其他环境中完成同样的工作要快得多。所以,我们过去常常问:“它能做X吗?” “不,不过这很容易。我明天就给你一个。”
随着软件工具概念的巩固,Unix 程序员对开发更多种类的专用工具以及更快地开发这些工具产生了更大的兴趣。
小语言
工具的概念被扩展到人们会使用工具来开发其他工具的范畴。因此,Unix程序员开发出了高度专业化的脚本工具,这些工具后来被称为“小语言”。Kernighan解释了他是如何理解小语言概念的:
后来有人邀请我做个演讲。我回顾往事,意识到这些年来我一直在尝试的各种方法,其实都存在一个共同的主题:那就是我一直在构建语言,以便更轻松地解决各种各样的问题。某种程度上来说,就是让用户更容易与机器交互。我开始统计这些语言,结果发现,哇,其中有很多东西都可以算作语言。有些是完全常规的语言,有些是运行在其他程序上的预处理器,有些不过是一些子程序的集合;但你知道,你都可以称它们为语言。它们的共同特点是规模相对较小,通常都是由一两个人完成的。而且它们都不是主流语言;我从未编写过 C 编译器。它们针对的是一些非常规的目标。所以,我说,哇,它们都是些小语言。
根据 Kernighan 给出的广义定义,诸如eqn、tbl和 之类的软件工具make可以被视为小型语言。脚本语言也是小型语言,因为它们简化了在诸如 C 语言之类的完整语言中会变得复杂的任务。
其中一种脚本语言是 ,awk由 Aho、Peter Weinberger 和 Kernighan 开发,用于“编写简单的单行或双行程序,作为大型流程的一部分进行一些过滤操作”。现代的 语言perl,一种在万维网上广泛使用的脚本语言,是 的后代awk。Kernighan 解释了 的起源awk:
我们当时有个东西叫qed……它是一个可编程编辑器,但它的可编程性仅限于某种形式上。它简直糟糕透了,然而它却是当时唯一一个能让你在程序中操作文本而无需编写大量繁琐代码的工具。所以我对可编程编辑器很感兴趣,那种能让你像操作数字一样轻松地操作文本的工具。我想这大概是我感兴趣的原因之一awk。还有一件事——我记得它像是一个触发点——是一个名叫马克·罗奇金德的人开发的一个非常非常专业的工具……他有一个程序,可以让你指定一个正则表达式和消息的序列……然后它会创建一个程序,当你把数据传递给这个程序时,如果数据是正则表达式的实例,它就会打印出相应的消息。
我们用它来做数据验证。我当时就想,这真是个绝妙的主意!这确实是个绝妙的主意。这真是个非常巧妙的主意。这是一个程序,它会生成一个程序,然后由这个程序去验证数据,而你无需自己添加所有繁琐的步骤。某个程序会为你生成这些步骤。它唯一的缺点是用途过于单一,仅限于这一个小型应用程序。因此,awk如果你愿意的话,我的贡献在于,你可以将这种理念推广到其他领域。
Weinberger解释说,其主要目的之一awk是提高Unix的数据库功能:
于是我们坐下来讨论了这些问题,数据库大致可以分为两部分。一是如何从数据库中提取数据,二是如何将数据存入数据库。而将数据存入数据库又涉及到“是否支持并发事务?”以及“是否需要加锁?”等问题,因为当时的Unix系统在这方面并不擅长,甚至根本无法胜任。这一切都太奇怪了。最终,我们决定开发一个工具,能够以更通用、更实用、更像数据库、更像报表的方式,从普通的Unix文件中提取数据。
awk使用类似于 的正则表达式匹配功能grep,但通过添加将原始表达式替换为所需数据流的功能,极大地扩展了该功能。
形式化方法
马克·泰格特
Unix 开发团队拥有深厚的数学方法背景。彼得·温伯格曾在密歇根大学担任教授,研究数论。布莱恩·克尼根的博士论文研究的是图划分。阿尔弗雷德·阿霍在研究生阶段辅修了数学。M·道格拉斯·麦克罗伊则表示:“我曾前往牛津大学一年,只为从源头汲取指称语义学的精髓。”
因此,Unix 团队在其发展初期就运用形式化方法也就不足为奇了。事实上,阿霍于 1967 年加入贝尔实验室,并立即开始研究如今已成为 计算机科学基础 的概念。在克尼根看来,
Unix 的理论基础可以追溯到 Al Aho,我想,他最初就是从这里(贝尔实验室)开始的——当时他刚在普林斯顿大学完成一篇关于一类特定形式语言的论文,曾与John Hopcroft共事,并且在研究生阶段一直与Jeff Ullman保持着最好的朋友关系。那时,形式语言分析是计算机科学的热门话题。虽然计算机科学在当时还不存在,但这却是当时的研究重点。人们研究语言的属性(尤其是那些对计算机有用的语言)。所以,当 Al 来到这里时,他仍然对这方面很感兴趣。我怀疑他的上司有时希望他能摆脱这些该死的语言研究,去做一些更有意义的事情。幸运的是,秉承着优秀的传统,他始终没有放弃。
在Unix的早期开发阶段,阿霍与人合著了许多与计算机语言和算法分析相关的标准教科书。有趣的是,所有这些书籍都包含了Unix编程的示例。通过这些教材,阿霍、霍普克罗夫特和乌尔曼将编程与Unix紧密结合,同时为编译器设计奠定了坚实的理论基础。阿霍指出:
因此,在 70 年代初期,我们(阿霍和乌尔曼)撰写了这套两卷本的《解析、翻译和编译理论》,试图提炼自动机和语言理论的精髓,并将其应用于编译过程。我认为这是为计算机科学的一个重要实践领域建立理论基础的一个有趣例证,也证明了编程语言和编译器领域的人员是计算机科学不可或缺的一部分。
阿霍和乌尔曼想要规范编程语言及其编译器的构造。阿霍回忆道:
我们在撰写解析理论著作时发现……我们发现,当时的文献——如果可以称之为科学文献的话——非常不准确。这些对象是如此新颖,处理它们的技术又如此不完善,以至于许多关于各种解析方法的论断都是错误的。那些证明根本站不住脚。因此,我和杰夫·乌尔曼(Jeff Ullman)所做的一件事,就是尝试理解可以用哪些技术来分析这些形式体系,并努力在科学文献中厘清哪些是正确的,哪些是错误的。
显然,阿霍对理论感兴趣,至少部分原因是为了理论本身。然而,贝尔实验室的理论研究远不止于理论本身。研究人员总是力求创造出有用的东西。阿霍报告说:
数学中心过去所做的工作也带有一定的咨询性质。其他部门会把我们当作顾问,随时可以请我们帮忙,理解对电话公司至关重要的现象。但他们被赋予了一项不受任何限制的授权,在解决这些特定问题时,能够自由发挥,也因此涌现出了一些极具创新性的解决方案。我认为计算机科学研究中心(Unix开发团队的所在地)继承了这种传统。我认为这是一个很好的传统。此外,对工作和人员的要求也非常高,无论谁加入,都必须是各自领域的领军人物,并且能够与该领域的顶尖专家交流。这可能也暗示着,真正的贡献不仅仅是撰写论文,事实上,在很多情况下,论文根本就没写过。真正的贡献在于提出想法,完善想法,并向人们展示如何运用这些想法来解决感兴趣的问题。
当然,其他人则持有不同的观点。作为Unix开发团队的经理,麦克罗伊认为理论仅仅是一种手段,而不是目的:
我们大多数人更偏向计算机领域,而非数学领域……我所在的部门既有像汤普森这样的系统构建者,也有像阿霍这样的理论计算机科学家。阿霍从 60 年代就开始耕耘语言理论领域……他大约在 66 年加入我们——和汤普森差不多同时。他发表了一篇又一篇论文,阐述了略有不同的解析和自动机模型。而这一切都基于一个显而易见的理念:总有一天,这些理论会真正应用于计算机实践……当完善的解析理论被应用到编译器编写系统中时,它就为大众所用了。的确,在某些情况下,理论无疑对我们的工作产生了影响。在很多其他领域,理论也是一种灵感来源,或者说,它潜藏在你的脑海中。
尽管麦克罗伊将理论置于“我们所做的事情”之下,但他意识到理论是绝对必要的:“我认为,yacc[另一个编译器-编译器]才是grep人们所推崇的‘真正的工具’——而我们正是在这些工具中找到了强大的理论基础。”
有趣的是,由于Unix开发团队的一些成员持有务实、工具导向的观点,他们以一种略显奇特的方式构思基于理论的想法。例如,在Unix项目刚刚启动时,Stephen C. Johnson请Aho为他编写一个C语言解析器。Aho回忆道:
我当时傻乎乎地决定手动构建解析器,采用的是语言理论中的一种形式化方法——LR解析器构建技术。我用一张巨大的纸——或者说一大块硬纸板——在上面构建词项集合,通常一边看电视一边做,因为这活儿实在太枯燥乏味了。当然,我没能成功。我把这张硬纸板给了史蒂夫,让他把代码编码到他的电脑程序里。过了一段时间,他被我搞得越来越沮丧,因为我总是做不好,于是他自己写了一个程序来自动构建解析器。这个工具就是这样yacc诞生的。
在 诞生不久后yacc,贝尔实验室的另一位科学家迈克尔·莱斯克(Michael Lesk)创建了lex,一个用于创建词法分析器的工具。lex可以生成程序,将程序员刚刚编写的原始文本中的字符分组为词法单元。然后,由yacc生成的编译器可以将这些词法单元映射到目标代码,也就是计算机实际运行的二进制代码。因此,通过输入lex正则表达式(来自语言理论的形式化方法)、上下文yacc无关文法的规范(来自语言理论的另一个形式化方法)以及与每个语法单元相关的操作代码,就可以自动构建编程语言的编译器。
显然,这种自动化依赖于相关的形式化方法。Unix 小组需要理论。Aho 指出,
嗯,用临时方法什么都能做,但是……至少我的观点是,如果你有一个科学的基础来衡量性能,并且能够基于这种科学理解迭代和改进你的算法,然后在此基础上构建工程设计理论,那么你在工作中以及一些编译器构建工具方面将所向披靡……另一方面,它还能显著提高软件质量和生产力,因为使用这些工具编写编译器比从头开始要快得多。以前,第一个 FORTRAN 编译器耗费了数十年人力才完成,而现在,你可以在本科计算机科学课程的课堂项目中构建一个编译器——一个功能强大的编译器。
显然,理论具有实际价值。形式化方法通常能够提高效率并编写简洁的代码。在温伯格看来,
如果你写的是一个基于理论的程序,你可以相信你已经修复了最后一个bug。如果你写的是一个拼凑而成的程序,那它就全是bug——只是被一些勉强能运行的东西包围着。你永远也修复不了最后一个bug。所以,我们有两种程序。这部分取决于程序员的编程风格。两种程序都有用。但其中一种更容易解释和理解,即使它并非更有用。
阿霍比温伯格更重视形式技巧,他在以下故事中便有所体现:
前一年,道格·麦克罗伊(Doug McIlroy)有个暑期学生,他用机器语言编写了一个经典的算法,该算法利用正则表达式构建确定性自动机,并寻找其中的模式。我惊讶地发现,我编写的程序运行速度比这个机器语言程序快好几倍。事实上,此后几年,这几乎成了我的业余爱好,而该程序的性能提升也几乎达到了两个数量级……
毫无疑问,Unix 团队从形式化方法的使用中受益匪浅。
然而,形式主义有时会显得繁琐低效。温伯格对早期版本的基本方法进行了yacc如下评估:
理论是正确的,定理也是正确的。但实际应用却并非表面看起来那样。你会发现……这才是令人恼火的地方之一。另一方面,如果你不以理论为基础,那就只会一团糟;你会说,“嗯,我可以破解它。”我们有一些程序并非基于理论,而我们一些相当成功的程序也并非基于理论。
此外,Unix 的创建者有时也会无意中做出一些理论发现。在开发实用工具的过程中,他们会提出新的理论。例如,鲍勃·莫里斯在实现高效的数学例程时,就提出了一些可以发表的技术:
总的来说,当我编写正弦、余弦、正切、指数和对数函数之类的函数时,我非常努力地尝试,并且取得了一定的成功,首先是把工作做得非常好,其次是其中具有足够的原创性(即理论),以至于我所做的这类工作大部分都得以发表。
事实上,克尼根认为,实际问题对理论发展产生了重大影响:
我认为[yacc]之所以成功,除了参与者的内在才华,以及他们选择了优秀的算法并在多年来不断改进之外,我认为还在于其他人不断尝试、探索和构建它的环境——最终形成了一个集合,你可以审视它并说:“是的,这确实有用。这不是学术练习。这确实比你以前用过的方法更好。”
因此,实用性主导了Unix小组的工作。然而,许多活动都被归类为“实用”。例如,对语言理论的深奥研究最终推动了编译器构造的自动化,因此也属于实用范畴。Kernighan详细阐述了贝尔实验室科学家是如何被评判的:
我认为,最终的评判标准是影响力,但这里需要从长远角度来看待影响力,也需要从更广泛的角度来理解影响力的含义。所以,如果有人从事纯粹的理论研究——但如果他的理论研究在某种程度上影响了学术界,无论是其他人借鉴并创造出实际成果,还是因为他能够塑造某个领域等等——这都没问题。这是很好的研究。它具有影响力。这并不意味着你能从一部手机或其他类似产品中看到这种影响;它指的是它对某些实质性事物产生了影响——一种积极的影响。
如此一来,Unix 小组实践了一种独特的理论。对于 Kernighan 而言,
……编程至少与纯数学家的工作不同;此外,如果你做得好,还能获得实用价值的回报。人们会走过来对你说:“嘿,看我做了什么!”也许数学家听到别人说“哦,我用了你的定理”时不会感到高兴。但我认为,当有人走过来对你说“嘿,我用了你的程序”时,编写程序的人会感到非常兴奋。
因此,Unix 的创建者们重视理论的实用性。在谈到awk由 Aho、Weinberger 和 Kernighan 发明的脚本语言时,Weinberger 指出,“与它能做一些有用的事情相比,程序的其他很多方面都无关紧要。”他在另一处也这样说道:
当你证明一个定理时,你现在知道了一些你以前不知道的东西。但当你编写一个程序时,整个世界都改变了。你可以做一些以前做不到的事情。我认为人们会被……这类事情所吸引。我一直觉得思考很费力。任何你能让计算机完成的事情——那都不能算是思考……一旦程序运行起来,它就一直运行着,如果它还能为你进行各种形式的计算,那不仅速度更快,而且比你一遍又一遍地手动计算更准确……
简而言之,形式化方法是 Unix 架构师工具箱中强大而实用的工具。
阁楼
如果Unix程序员们身处不同的工作环境,他们开发软件工具的速度或许会慢很多。Unix活动的中心是默里山六楼的一间房间,里面放置着运行Unix的PDP-11计算机。“别想象成什么豪华实验室,那只是阁楼上的一间房间,”莫里斯这样描述道。除了程序员之外,专利部门的四位秘书也在阁楼里工作,负责Unix最初开发时所设想的文本处理任务。莫里斯这样描述当时的工作环境:
我们都在同一个房间里工作。我们挤在默里山六楼阁楼的房间里,那空间大概是这家酒店房间的一倍半。我们坐在相邻的终端机前,彼此都很熟悉,而且总是一起吃午饭,共用一个咖啡壶。所以,我们关系非常密切,大多数人既是用户又是贡献者,而且在各个方面都积极主动地进行研究贡献。
程序员独特的工作环境促成了思想的自由交流和信息的完全共享。此外,紧密的团队氛围也使程序员之间形成了一定的礼仪规范。Cherry 举了一个例子:
当时有一种观念,谁最后碰了什么东西,它就归谁。所以,如果你需要pr做某件事pr却没做,然后你去把它加了上去,那么现在它就归你了pr。所以,如果它的其他部分坏了,你也得负责。
尽管更换工具带来了额外的责任,但程序员们毫不犹豫地进行了他们认为必要的任何改进。例如,莫里斯修改了……pr,正如他解释的那样:
例如,我记得我曾经对一个软件做过一个显著的改动。大约在1974年的某一天,我听到肯和丹尼斯在争论某件事发生的时间,即使到了那个时候,他们也无法就这件事发生的年份达成一致。他们面前放着一张打印出来的纸,上面写着日期——月份和日期。我看了看他们,又看了看那张纸,听着他们的争论,然后用我最地道的南方口音说了句“哎呀,糟糕”,接着转身走到控制台前,修改了名为“print”的打印程序pr,现在它就能打印出年份了。
Morris 非常赞赏这些工具易于使用和维修,甚至在问题被提出之前就能将其解决。
有一天,大概是1973年左右,我正在看丹尼斯·里奇做一些算术运算。不是什么复杂的运算。他只是在用某种程序计算一串数字的总和,dc输入的时候不小心输错了,dc原因也没什么特别的,就是程序本身的设计就是这样——它本来可以只打印一个错误提示,但它没有——它不仅打印了错误提示,还把当前的总和清空了。所以他不得不从头再来,而我又用我最爱的南方口音,打开程序,修改了第一个程序,dc重新编译并安装,大约十分钟后,程序运行了。丹尼斯可能没注意到我在看他,他说:“你的程序有问题,我觉得应该帮你修一下。” “嘿,它已经安装好了。”这种事情可能发生在任何人、任何软件、任何时间,而且是常态而非例外。
这个例子说明了阁楼中开放、合作的环境如何提高了系统的响应能力和灵活性。
更重要的是,每位程序员都亲自使用所有工具,因此能够以在其他环境下无法实现的方式对工具进行修正和改进。正如莫里斯所解释的,参与该项目的任何人都不能不是程序员,否则就无法成为用户。
我既是用户,也是贡献者,我创建了一个系统,其中很大一部分功能是我自己想用的。所以,我创建的很多部分正是我自己工作需要的。因此,我既是用户又是贡献者。但这种情况很普遍,几乎每个人都是如此。
他特别讨论了他的计算器程序dc:
虽然我写[ ]不是dc为了公开,而是为了我自己,很多软件都是这样,人们大多按照自己的标准编写软件,按照他们想要的方式,供自己、朋友和同事使用。
同样,Kernighan 认为,没有人能在 Unix 系统中成为程序员,除非他曾是该系统的用户。
我们只用自己的产品,我认为这是关于我们这个团队的一个关键点。我们不为别人开发工具,也不为别人开发任何东西。粗略地说,我认为为别人开发东西是不可能的。
他继续说道:
如果我为你打造某样东西,即便你花了很多时间向我描述你的需求以及它为何如此,最终的效果也不会像我亲自面对问题时那样成功。当然,如果我和你相处足够长的时间,我或许能逐渐理解你的问题所在,那时我可能会做得更好,但我认为,从历史上看,我们最擅长打造解决自身问题的产品。我们之所以能如此深刻地理解这些问题,是因为我们亲身经历过,要么是直接面对——你知道,我自己就面临着这个问题——要么是隔壁办公室的同事面临着这个问题。
这种环境不仅孕育了工具箱的概念,还孕育了一整套编程理念。
文本处理和写作工作台
大卫·西尔弗曼
Writer's Workbench 体现了 UNIX 团队的协作精神。Unix 项目的成员一直从事文本处理工作。他们编写和编辑代码,创建了 Unix 及其工具。此外,该项目还从专利部门获得了资金,以换取一个文档处理软件包。经验丰富的程序员 Lorinda Cherry(1969 年毕业于史蒂文斯理工学院,获得计算机科学学位)和 Brian Kernighan 构建了一个开放式的文本处理程序系统。他们在格式化、文本分析和样式方面的工作促成了troff、ntroff和Writer's Workbench 的诞生,这些程序至今仍在使用。
文本处理之所以受到关注,有三个因素:内部使用、词性分析程序以及文本统计分析。随着各个团队探索或需要新的文本处理方法,相关工具的数量也随之增长。团队利用文本处理来开发程序和撰写报告。此外,Unix 团队的一些改进工作也促进了新工具的完善。Cherry 自述的目标是“看看我能让计算机做哪些有趣的新事情”。尽管 Unix 自诞生之初就使用了文本处理器ed,但 Kernighan 和 Cherry 不仅改进了ed的原有功能,还为其创建了新的功能。
首批改进是troff和ntroff命令。根据贝尔实验室技术期刊(Kernighan、Lesk 和 Ossanna,2019 年)的描述,这些命令“通过提供灵活的基础工具而非特定功能,简化了各种格式化任务”。结合上文所述的小型编程语言(尤其是eqn),这些功能使得在计算机和打印文档中都能进行文本处理和格式化。这对于像贝尔实验室这样拥有大量技术报告的公司来说尤为重要。
第二个辅助文本处理的项目是布伦特·阿克尔(Brent Aker)开发的Votrex机器,这是一种可以代替计算机发声的外设。Votrex无法正确地发出语调或重音。切里(Cherry)开发了一个词类识别程序,使计算机能够正确地发音。计算机需要“用于音节重音的词类识别”。
第三个项目是鲍勃·莫里斯和李·麦克马洪对《联邦党人文集》作者身份的研究。莫里斯和麦克马洪运用统计学家弗雷德里克·莫斯特勒的理论,试图通过统计分析来确定每篇文章的作者。他们“轮流打字”,将文章输入机器,让机器通过各种过滤器和计数器进行处理。在此过程中,他们“开发了许多文本处理工具”。例如,Typo 就是“早期拼写检查器之一”。它的工作原理基于三字母组统计,这是一种莫斯特勒的技术,用于分析重复字母的片段。切里对三字母组统计的熟悉源于她1976年参与的一个压缩项目。她这样描述当时的流程:
如果你的十个字母组成的字符串中有一个六字母的三元组,其计数足够高,值得提取,那么你就取出整个六字母字符串,将其存储在字典中,然后用一个字节替换它,再用字典中的索引替换它。
这种计数方法也被应用于其他形式的分析,例如《联邦党人文集》的作者研究。
Unix 的特殊功能使得许多文本处理工作成为可能。由于Unix是通用操作系统,“最初为其他用途编写的程序”也可以用于文档处理。例如,早期的拼写检查器就利用了sort命令。“大小写识别”(随着 Unix 的发展而变化)也增强了程序员分析文本的能力。新的“标点符号、空格和大小写识别”方法也做出了贡献。
凭借在格式设置、词性分析和统计过滤方面的背景知识,Cherry 着手开发Writer's Workbench项目。作为这一新型辅助工具的“鼻祖”,Cherry 创建了一个能够分析写作风格、判断可读性并帮助用户写出优秀文章的文字处理器。
Cherry从一位同事那里听说,普林斯顿大学英语系的讲师Bill Bestry让他的学生“统计词性”。学生们随后能够利用这些客观的统计数据来改进写作。基于Cherry之前在词性方面的研究,Writer's Workbench可以自动进行统计。正如Cherry所说:
有很多东西需要通过词性来判断是复合句还是并列句,因此词性分析程序变成了风格分析程序。
这种“在风格和措辞之上叠加的层”特性,为贝尔实验室的学生和同事们提供了更广泛的功能。例如,“皮斯卡塔韦有一个人因工程小组”,他们希望“审视(计算机)文档,并从人因工程的角度判断其是否合理”。Workbench 的可读性指标有助于编辑 Unix 系统本身的文档。
在科罗拉多州立大学的beta测试期间,Workbench得到了教师和学生的积极使用。该程序的成功主要归功于三个方面:可靠性、结构以及程序员对写作过程的深刻理解。与之竞争的IBM产品Epistle基于解析器,速度缓慢且无法处理学生语法错误。Workbench “从未真正检查过语法”,但它能够清晰地展现句子的风格。Workbench“不计后果地进行检查”的态度最终确保了整篇文章的准确性。然而,最重要的因素是程序员对写作过程本身的理解。他们知道应该将可读性评分作为估算值,而不是将文章生硬地套用数字。他们明白,最终的目的是让学生明白写作是一系列选择的过程,而不是在激光打印机上进行漂亮的排版。Cherry表达了她对Workbench使用方式的愿景:
我对很多这类工具的看法是,它们在教育中的价值在于,它们能提醒正在学习写作的人,他们在写作时是有选择权的,而且他们确实需要做出选择。他们通常不会把写作任务本身看作是做出选择的过程。一旦把内容写在纸上,他们就觉得已经定稿了。所以,这些工具会促使他们进行修改。
正是这种超越格式化的进步,使得 Unix 真正能够处理文本并提高用户的写作能力。
精神气质
罗伯特·默里-拉斯特和马利卡·塞思
Unix操作系统的创建是众多数学家和理论家共同努力的成果,该项目的成功很大程度上归功于参与者以及系统编写的环境。与大多数企业不同,贝尔实验室的工作氛围轻松,没有为个人分配具体的任务。据在加入Unix项目之前曾在贝尔实验室与同一团队共事的Kernighan回忆,每个人都可以从事自己感兴趣的项目:
真有意思,我在1967年和1968年在这里过得非常开心——你知道,就是因为这里的人。这里聚集了一群非常棒的人,我很享受这段时光。我从未面试过其他地方;我甚至从未想过其他地方。我只是说我想在这里工作。萨姆·摩根很有远见地说:“我们不想招任何博士辍学生,所以你必须完成你的学位。但除此之外,当然,我们非常欢迎你。” 就这样,我在1969年初就来了,而章程,或者说我的工作指示——就像对其他人一样——根本不存在。你想做什么就做什么。
希望在于,你身边的人都在做着有趣的事情——或许最终会有意义,但未必立竿见影,我也不确定——但你身边的人都在做着有趣的事情,而且我认为,他们从这些有趣的事情影响他人中获得的快乐,意味着你自身也会产生一种温和的引力,促使你去做同样的事情。显然,奖励机制最终会偏向那些对当地社区、贝尔实验室社区、AT&T以及科学界产生影响的人,无论这些影响是多方面的。
同样,鲍勃·莫里斯认为研究人员的自由至关重要,而且在其他任何时期都不可能实现。
……总体态度。参与系统软件开发的人员,而且至关重要的是,他们并非来自外部独立的部门。我们又不是在竞标什么该死的政府项目。这意味着,一些对系统运行方式一窍不通的人制定了一大堆方案……我们在这方面几乎拥有完全的自由,而且我们确实做到了,这是一种奢侈。我的意思是,现在没人能用Unix做这种事了。绝对不可能。AT&T的Unix不行。任何Unix都不行。你不可能看着程序出了这么大的问题,然后哈哈大笑。发现问题后,进去找到需要修改的地方,然后安装修改后的代码。嘿,这在1974年完全合理。到了1978年,就完全不可能了。
从管理层面来看,这种自由理念以及重视个人项目的重要性体现在摩根的招聘实践中。摩根表示:
我们的理念是,聘用聪明的人才,让他们接触有趣的问题领域,并密切关注他们的工作,尤其是他们与他人的互动。我们只尝试以非常概括的方式给予他们指导。通常,这种指导就是对他们正在做的事情充满热情。只要保持高标准的招聘要求,管理层保持警惕,这样的环境就能自我维持。
Unix项目的另一个独特之处在于,项目经理都是受过专业技术培训的人员,他们的资质与工具开发人员相当。摩根说:
贝尔实验室的管理层,至少在研究领域,都是从技术岗位一步步晋升上来的。在这里,研究领域的人只有拥有出色的业绩才能升到管理岗位。你可能会遇到一些不同意这种观点的人。但我认为,我们的部门主管、主任和执行主任都曾是技术精英。有时候,这种晋升方式也会适得其反,因为你会遇到一些技术精英,但他们缺乏人际交往能力。但这又是另一个故事了。你们的技术人员和经理都曾是技术精英,他们深受这种研究管理理念的影响,这种理念指导着如何在这样的机构开展和管理研究。而这种研究管理理念也带来了诸多益处……我并非这一理念的创始人,但我在某种程度上延续了它。
摩根认为,给予人们完全的自由和分配任务之间存在着微妙的平衡。此外,他只在认为团队准备就绪时才会明确批准某些项目(“选择性热情”),例如,当汤普森的团队请求使用电脑时。用摩根的话说,
你不可能强迫他们成功。你应该招募聪明的人才,为他们提供一个充满激励的环境。然后,你要对他们的工作进行有选择性的筛选和鼓励。但你不能操之过急。正如我所说,汤普森和他的团队第一次提出要一台电脑,他们想要一台DEC PDP-10,但被拒绝了。这台电脑体积太大,而且在Multics项目刚刚结束之后,你不可能马上就着一台大型电脑做操作系统研究。他们第二次提出要一台PDP-11/20,我说:“我还没被说服,我想看看你们打算用这个文本处理系统做些什么。”
所以我没有直接拒绝他们,但也没有签署他们的订单。他们找到了其他人,另一位主管签署了订单。第三次他们提出要一台11/45,这时他们已经有了一套完全合情合理、站得住脚的理由。所以,他们得到了有选择性的热情,但这种热情既不会过于强烈,也不会持续时间过短。如果它真的好,自然会证明这一点。
同样,克尼根也认为该组织没有直接的管理,其成功既是偶然因素,也是相关人员的功劳。他解释说:
我不认为这件事是有人指使的,或者至少,即便有人指使,也处理得极其巧妙且不引人注目。也许管理层会说那样更糟……如果真是这样,那也算是他们的功劳。现在,我认为,从某种意义上说——我的意思是,道格至少参与了其中一部分的管理。我猜肯名义上是道格的部门员工,而道格在这方面非常出色。就他管理这件事而言,他会在恰当的时机提出极具建设性的批评,并且亲自去尝试你的工作,找出哪些地方有效,哪些地方无效,然后告诉你哪些地方做得好,哪些地方做得不好。在某种程度上,我怀疑我们所有人都在做着类似的事情。我不认为这件事是由任何直接管理人员做的,所以我们可以排除这部分因素。
一部分原因是优秀人才汇聚一堂,而且他们的品味也相当不错。尤其是肯和丹尼斯,据我观察,他们确实拥有深刻的洞察力,同时品味也很好,而且他们的品味非常接近,所以不会朝着相反的方向发展。另一部分原因则是幸运的巧合,技术发展到了一个恰到好处的阶段,你可以拥有一台硬件——一台可以工作的机器——在某种程度上,你不必受制于他人。你不必因为别人付了钱就按照他们的方式使用机器;你可以拥有某种程度上属于自己的东西,从而按照你想要的方式,按照你觉得舒适的方式来构建你的计算世界。
鲍勃·莫里斯也谈到了道格·麦克罗伊在项目中的管理和技术层面所扮演的角色。莫里斯叙述道:
道格当时是位经理,而且无论如何,他对整个项目都负有监督责任……他是部门主管,我认为这项工作是由他部门的人负责的。或许会有例外,但大部分肯定都出自他的部门。所以,在初期阶段,他只是观察着这一切的发生,觉得这是个好主意,便予以支持,并在行政方面提供帮助。或许几年后,他就和其他人一起积极参与其中,在技术层面上推动项目进展。这就是为什么我把他放在这个阶段的原因。我指的不是道格作为经理或部门主管的身份,而是他作为技术人员的身份,大约在1973年左右就参与其中了。
与此同时,他感到项目过程中缺乏明确的领导,并强调了亲力亲为的重要性。莫里斯评论道:
当时的氛围更注重合作。我觉得从来没有人有过想要承担领导责任的想法。如果肯让别人做点什么,得到的回答总是“去吃葡萄柚吧”……哦,不管他让谁做,答案都是如此。或者如果小组里的某个人被要求做点什么,答案就是“自己去做”。我感觉不到任何领导的存在,因为身处社群之中,就意味着团结协作。
此外,他们对工作质量有着强烈的责任感,因此项目都以理论为支撑。根据温伯格的说法,
……在Unix开发领域,确实存在一种趋势:如果你不知道如何正确地做事,那就干脆别做了。我认为,这正是导致人们倾向于选择那些有理论支撑的东西的原因之一。
因为我总觉得我会犯错,每个人都会犯错,而且我也总觉得你永远都不想再碰那些程序。所以,尽早把事情做好很重要,这样它才能一直有效……这不仅仅是眼前的问题,虽然我们写了很多代码,这些代码确实是为了解决眼前的问题。它必须能够永久地填补这个空白,这完全不现实,但这确实是一种态度。我认为这与另一点相符。如果只是草率地、临时地、拼凑地解决问题,那肯定行不通。你最终还得回来重做一遍,这太像工作了。当然,现实情况并非如此,但我认为这是一种态度。我认为这种态度更容易让人接受。
温伯格断言,尽管当时大力推行高质量的工作,
很明显,Unix 系统最强大的部分都具有理论驱动的特性,而很多部分,即使背后没有明确的理论基础,也能找到类似编程语言或设计工具的替代方案。Unix 就以“先做好 80%,因为剩下的 20% 太难了”的理论而闻名。但如果能省去一大块,那就去做。这就是为什么 Unix 会使用通用的正则表达式,而不是其他版本……我认为正则表达式显然是 Unix 系统区别于其他系统(例如 MS-DOS 系统)的唯一标志。是的,我认为妥协是在其他地方做出的,而不是在这些拥有强大算法的地方。
洛琳达·切里认为,这项工作的理论基础造就了一种严谨的态度。除非必不可少,否则任何东西都不会被纳入其中,而且人们在某种程度上必须为自己的工作做出解释。切里评论道:
当然,对于哪些东西可以保留、哪些东西不能保留,确实存在一定的纪律。这一点在任何编写的手册中都能看到,比如道格开始随意修改程序,或者其他人开始说:“与其记录这个文件,不如把它删掉。它其实没必要,还有别的方法。”
如前所述,这也体现了一种所有权意识,即最后修改程序的人拥有该程序的所有权。Cherry 认为,纪律和所有权这两个因素是这个 Unix 项目独有的。她将其与伯克利 Unix 系统进行比较,并指出这些差异可能是由于环境不同造成的:
如果你看看伯克利Unix系统,你会发现一些类似的命令,伯克利的命令和我们这里一样,但你看看伯克利的手册,他们给命令加了85个标志cat之类的东西。这本来是一个非常简洁优雅的功能,做事也很简单。我想我们一直秉持着这样的态度:只有真正有用的东西才值得添加进去。也许是因为伯克利的团队比我们小,或者伯克利的人都想找到自己的定位,所以他们必须给某些东西加上标志,我不知道那里的环境是怎样的。但我认为添加标志是为了防止功能主义。
我认为这是两个系统之间的区别。而且我认为这无疑与大学环境有关,在大学里,每个人都必须做点什么,而在另一个环境中,在某种程度上,每个人都必须向你的目标证明他们所做的事情是合理的。而且还有一些犹豫,因为一旦你动了手,它就归你所有了。你仔细考虑过是否需要添加那个标志,或者是否有其他方法可以绕过它。是否有其他程序可以实现。你说:“我会找到其他方法,因为我不想拥有这个程序。”
然而,与此同时,人们也乐于并被期望以任何可能的方式帮助他人改进他们的程序。这种积极响应的一个例子就是前面提到的鲍勃·莫里斯讲述的dc项目。正如这个例子所示,协作在项目的成功中发挥了不可或缺的作用。团队成员会讨论他们遇到的问题,并经常共同努力解决问题。AWK就是一个完美的例子,它是由Al Aho、Peter Weinberger和Brian Kernighan开发的文本处理语言。顾名思义,它绝非一人之力所能及。
麦克罗伊表示,随着管道的引入,协作的趋势愈发明显。这种方法的一个难点在于,他们必须格外小心,确保所有部件都能完美契合;当许多小部件组装成一个完整的项目时,部件之间的相互作用往往会导致错误。正是由于各个部件内部的高效运作,整个项目才得以成功。麦克罗伊说道:
这就是 Unix 的理念:编写只做一件事并把它做好的程序;编写能够协同工作的程序;编写能够处理文本流的程序,因为文本流是通用的接口。所有这些理念,构成了工具方法论,或许在管道出现之前就已经以某种不成熟的形式存在,但它们真正意义上的形成是在管道之后。
摩根认为,管理层鼓励这种合作,但有时也需要协助组织合作事宜。摩根观察到:
我们鼓励大家积极主动,如果他们想完成某件事,或者想找人合作……你偶尔会遇到有人想找人一起工作,但这只有在他们的上司说“你们俩合作”之后才会发生。没有人会直接告诉研究人员要合作。你需要找到彼此的共同兴趣,然后合作才会发生。所以,如果有人来找我说:“你去告诉某某某跟我合作”,你就得自己去建立人脉。因此,我们鼓励大家积极主动,建立人脉,促成合作。
紧密的工作环境促进了合作。阁楼在这方面起到了很大的作用,但成功也归功于在阁楼里工作的人们。摩根回忆说,这个团队关系非常紧密,即使不工作的时候也会聚在一起。用他的话说,
从大约1970年到1976年或1977年,我们团队大概有二十四个人,总共二十四人。我们基本上没有招人,正处于长期的招聘冻结期,只有一小群优秀的人,他们通常一起吃午饭,非常乐意互相争论、讨论,并运用他们所掌握的技术,把他们认为有趣的东西组合起来。当时,文本处理方面的工作量很大,操作系统开发方面的实际工作量也很大,理论计算机科学、编译器理论和算法方面的工作量也很大。这些工作基本上都是由少数几个人完成的。但他们彼此之间交流很多,也经常大声讨论,而且他们确实在合作。而这才是科研应有的方式。
这导致了阿霍所说的“Unix中的达尔文主义”。编程语言由用户进行测试,以便更好地满足用户的需求。阿霍说:
嗯,你(Mahoney)谈到Unix是一种精神。我的理解是,Unix中蕴含着大量的达尔文主义精神。如果我们探究某些命令和语言的起源,就会发现它们都源于某个人的想法。比如Kernighan和Cherry开发的用于排版方程式的语言。他们先开发出一个语言处理器的雏形,然后让朋友们试用。之后,这种语言根据使用模式不断演进。随着用户对语言的了解加深,他们会提出“我想要这些附加功能”或者“这门语言存在一些不便之处”之类的建议。因此,Unix语言乃至整个Unix系统都经历了达尔文式的演进。
它满足了特定用户的需求,并且有足够的时间对系统进行完善,使其能够高效且优雅地满足这些需求。有一种“欧洲模式”(如果你愿意这么称呼的话),或者说是一种更教条的语言设计方法,在这种方法中,一个权威委员会会召开数年的会议,最终制定出一个语言规范。他们……编写一份文档。编译器开发者们根据这份文档花费数年时间开发编译器,结果却发现语言设计中可能存在一些缺陷。而且,这个过程要繁琐得多。自然语言会不断发展,我想,“为什么编程语言就不能呢?”
Lorinda Cherry 还描述了自然编程语言的重要性,特别是提到了方程式:
……图形部分很容易。难点在于如何开发一种语言,让一个数学打字员也能轻松上手,流畅地绘制出复杂的图形。我认为语言本身才是它的精妙之处。现在依然如此。
Morris 也描述了建立直观数学程序的同样必要性,同样提到了方程式:
……这玩意儿应该能用,而且应该用显而易见的方式运作,但我没有说明书。我没打算买,也从来没想过要看。[布莱恩·克尼根]的观点完全支持我的看法……他的观点是,如果我运用常识,尝试构建某种结构,比如我写出“从A到B的X的积分”,它就应该理所当然地生成一个漂亮的积分符号,积分下方有A,积分上方有B,以及被积函数,所有这些都应该在不费吹灰之力的情况下完成。如果它不能识别出普通人理解的常识,也就是普通人编写的数学文本,那么它就应该被修改。
就这样,它一直保持着原样。我仍然在使用eqn ,但我至今从未见过eqn的说明书。这是少数几个可信的例子之一。因为可能存在的差异实在太多了。我的意思是,看看那些同类竞品,简直让人无法使用,因为你必须学习很多规则才能操作它们,等你学会一半的规则时,你已经对整个软件感到厌倦了。
莫里斯很早就向康登传达了这一点,康登也表达了类似的感受,并将其描述为“认知工程”。他提到曾去找鲍勃·莫里斯询问此事。
“你怎么理解这些命令的作用?手册上的说明不是很清楚。”[莫里斯]会说,“你觉得合理的做法是什么?” 做些实验,找出答案。我认为这是一个非常有趣的线索。至少他的理念,以及丹尼斯等人的理念,都体现了系统命令应该如何运作。它应该以一种易于理解的方式运作。它不应该是一个复杂的功能,所有功能都隐藏在一堆规则之中。我认为认知工程的概念……是人们会形成一个模型。你给他们一些仪器、工具,比如水龙头、电炉之类的东西,并演示它们的工作原理。
然后,他们在脑海中形成一个模型,展示其内部运作方式,以帮助他们记住将来如何使用。这可能完全是错误的模型,与黑匣子内部的运作方式不符。事实上,我认为鲍勃·莫里斯[告诉]我,我知道他是这么想的,黑匣子本身应该足够简单。例如,当你构建一个关于黑箱内部运行机制的模型时,这个模型实际上就是黑箱内部正在发生的事情。[不要]编写程序试图欺骗和猜测他们想要做什么。你应该让程序清晰地表达它的功能。
这种清晰性是Unix哲学的核心特征。Unix诞生于一群才华横溢、充满热情、背景多元的人们之中。他们被赋予了充分的自由去创造自己的项目,而Unix系统则是在各方贡献的基础上发展而来的。当时并没有固定的组织结构,工具都是按需编写的。许多工作都建立在坚实的理论基础之上,从而造就了严谨的编程规范。协作也是成功的关键,而紧密的工作环境则进一步促进了这种协作。研究人员们在阁11里一起工作,并在工作之余继续讨论。他们力求开发出直观高效的程序,而这些特质在其他环境下或许难以复制。
Unix 的传播,重点关注贝尔实验室内部发生的事情
史蒂夫·陈
Unix操作系统最吸引人的特点之一就是它的高效性。Unix的这一特性源于两个因素。首先,贝尔实验室的研究人员在开发Unix时,正致力于小型计算机的研发。其次,对效率的追求是对Multics复杂性的自然反应,Multics中包含大量与操作系统本身无关的代码。肯·汤普森和丹尼斯·里奇深谙如何在不损害操作系统功能的前提下,精简某些代码。
Unix操作系统在AT&T和贝尔实验室的发展历程,与Unix的开发理念相辅相成。Unix在贝尔实验室的推广并非管理层刻意为之,而是通过技术需求和技术交流自然传播开来。Unix的流行并非源于大规模的广告宣传,也并非高明的市场营销策略。贝尔实验室的各个部门之所以了解Unix,仅仅是因为它是当时最高效、最灵活的操作系统。
Unix 拥有诸多优势。首先,它使用高级语言 C 编写,而非像几乎所有之前的操作系统那样使用汇编语言。这反过来又提高了可移植性。Unix 最终成为唯一一款既能在超级计算机上运行,也能在微型计算机上运行的操作系统。此外,管道的概念使得进程之间可以进行流式传输。伯克利系统发行版 (BSD) 添加了许多网络功能,例如套接字,而许多软件工具则随 System V 一起推出。Unix 对文件和设备的处理方式简洁明了。它足够灵活,可以应用于各种规模的系统,其工作台概念为用户提供了一套易于扩展的工具集。
在退出 Multics 项目后,贝尔实验室的研究人员正在寻找 Multics 未能实现的操作系统,而贝尔系统则面临着利用小型计算机实现电话业务自动化的难题。据伯克利·塔格 (Berk Tague) 所述:“在 20 世纪 70 年代初,我们发现有必要——或者更确切地说,有机会——利用这些小型计算机来支持电话公司的运营,这促使我们开始使用 Unix 系统。我们知道,在维护、流量控制、维修和会计应用方面,我们可以做得更好。”(《伯克利·塔格访谈录》,《Unix 评论》,1985 年 6 月,第 59 页。)塔格继续说道:“现有的系统由人工和纸质文件组成。在 20 世纪 70 年代初,电话业务面临着被 20 世纪 60 年代的繁荣所淹没的危险。当时人们对使用计算机来帮助管理这部分业务产生了浓厚的兴趣。”进入20世纪60年代末期,纽约公共服务委员会和其他监管机构开始向AT&T施压,要求其解决所谓的“服务危机”。这种压力促使AT&T寻求能够提高其支持运营效率的技术进步。最终,这一探索催生了Unix操作系统。
起初,AT&T曾考虑从外部供应商采购操作系统。然而,事实证明,当时可用的供应商操作系统根本无法满足需求。此外,与此同时,许多人已经开始开发自己的操作系统。因此,AT&T决定自主研发Unix系统以满足自身需求。
伯克·塔格在支持Unix系统方面发挥了重要作用。他曾担任计算机规划部门主管,负责系统工程。正是塔格力主采用Unix,并制定了内部标准。1973年9月,他成立了Unix开发支持组织,专门负责为标准Unix提供支持。在接受迈克尔·S·马奥尼的采访时,塔格讲述了他如何开始接触Unix。
我于 1973 年 9 月开始涉足 Unix 领域……并获准在贝尔实验室组建第一个 Unix 支持小组。我组建了一个管理团队并配备了人员。当时,我也对支持 MERT 很感兴趣。我的想法是,MERT 用于实时计算,而 Unix 用于分时应用。但 MERT 最终未能成功。我们在那上面浪费了精力。尽管 MERT 实际上被嵌入到一些支持 ESS 处理器的 Unix 系统线中……但我的动力来自客户。当我开始做这件事时,我的所有客户都比我的员工更了解产品。
因此,我们花了第一年时间编写产品文档,并向西部数据公司提交了 LDI(产品设计信息),使其成为正式产品——这是必须完成的。我的员工也在努力学习,以便像他们的客户一样了解我们的产品。但我们很快就明白了业务的本质,并试图掌控客户……最终,我们不得不把很多东西都用Unix系统来支撑起来。(伯克·塔格,迈克尔·S·马奥尼访谈录)
该组织与贝尔实验室研究部门一致认为Unix需要具备可移植性。他们的目标是使Unix成为硬件和软件之间的接口,从而使应用程序能够在底层硬件发生变化时继续运行。Unix后来用C语言重写,这意味着它不再依赖于特定的机器。用C语言重写Unix的决定是由Ritchie和Thompson提出的。这对于Unix操作系统的可移植性而言是一项重大突破。Tague回忆起他第一次售出Unix的经历。
我清楚地记得我卖给第一个Unix的人。当时在惠帕尼,有个家伙从Safeguard挖来了一批相当不错的编程人才。他们以前只为大型机器写过代码,从未开发过操作系统、编译器,或者任何复杂的系统软件。他们当时有个计划,要买一台PDP-11,开发一个操作系统,编写自己的语言,然后编译一个应用程序,准备在春天投入使用。我来考察这笔采购。我和……一个叫Jan Norton的人坐下来聊了聊,我们很快就针锋相对。我说:“听着,我知道你们可能想要世界上最便携的操作系统,但我坚持要你们选择Unix,并以此为基础进行开发,因为它能让这台机器运行起来。
如果你们不这么做,那就一点希望都没有。”我敢打赌。”所以我说,“你们可以自己开发操作系统。”当然,我知道当他们把这玩意儿装好之后会发生什么,他们也真正意识到自己面临的挑战。UNIX 是他们唯一能按时完成任务的希望。事实也的确如此……我跟好几个人重复了这个过程,PDP-11 DEC 的口碑很好。显然,他们喜欢这台机器。(同上)
Unix之所以畅销,是因为它是当时最有效的操作系统。伴随Unix而来的是各种软件工具,例如程序员工作台,以及一支负责操作系统支持的技术人员队伍。这种市场推广和支持模式与贝尔实验室的电话系统如出一辙。
为Unix提供支持是塔格在贝尔实验室工作的重要组成部分。从这个意义上讲,销售Unix就像销售电话系统一样。你不能仅仅把产品卖出去就完事。销售Unix的同时,也需要招募人员来提供Unix的支持。
我一直认为这个行业有三个层次。始终存在着顶层、中层和小型企业。这些层次的定义随着时间的推移而有所变化,但从大约 60 年代末开始,我总能找到这三个层次,它们的划分不仅取决于机器的规模,还取决于营销方式的捆绑式模式。这种模式涵盖了从大型企业到小型企业的各个层面,大型企业的特点是:当你购买一台机器时,我们会派人到你的场地。一切都是打包好的。当然,解绑式营销在一定程度上冲击了这种模式,但它仍然源于这种传统。这种模式仍然非常普遍。”(同上)
谈到贝尔实验室对Unix的支持时,塔格说:
很明显,人们需要对 UNIX 进行集中支持。对于开发人员来说,从研究部门获取未经注释的批处理文件或代码通常是不可能实现的。但你看,这些人已经把自己(套牢)了。因为他们承诺要从头开始编写自己的操作系统。所以我可以指出:“听着,你们终究要维护一个操作系统,所以你们最好支持一个现有的。别跟我说自己写一个更容易,也别跟我说打败这个正在开发第三个操作系统的人更容易。” 那时,这个项目已经开始取得一些进展。所以这确实是一个卖点。但我知道,如果我们有集中支持,事情会更容易。所以我去找了我的老板,实际上我们达成的协议是将规划部门分成两部分。我接管了其中一个部门,后来发展成为 UNIX-MERT 开发部门……
谈到 PWB 程序员的工作台——一套最初独立开发但最终发展成为 Unix 系统不可分割的一部分的工具——Tague 说:
迪克和他的团队在印刷电路板上开发了一些非常好的工具,用于管理代码、进行代码控制等等。迪克对此不太有耐心,但他很感激;他的经理们需要这些工具。我们把这些工具比作经理们的“救命稻草”,这在某种程度上也算贴切。(同上)
显然,Unix 是一款极具市场潜力的产品。然而,它仍需从研究领域过渡到销售领域。此外,为了将其作为一款市场产品推向市场,还需要对 Unix 进行标准化。Tague 在推动这一过渡过程中发挥了关键作用。
当有人向研究部门提出将Unix作为产品进行市场推广的想法时,该部门并没有积极响应。尽管如此,研究部门最终还是同意了塔格的提议。
……我当时设想,我们应该能够将Unix作为操作系统,但作为一家公司,我们可以将其作为内部标准操作系统,并与C语言一起在一个环境中运行。然后,我们可以为大型外部机构和商业机构提供前端支持。我的想法是,人们会看到这台机器,并使用一个统一的界面。这个想法最初并没有得到研究部门的认可……我的经历是,他们可能并不欣赏,但最终一切都实现了。这基本上就是公司业务发展的真实写照。(同上)
在对塔格的采访中,马奥尼问道:“你当时是否在某个时候决定接管最新版本的Unix并将其标准化?”塔格回答说:
是的,正如我所说,在 1973 年,我们显然需要支持,而正确的做法是去研究部门告诉 Ritchie……我们在这方面配合得相当不错,我的团队负责整理设计信息文件以及 Western 要求的其他资料,以便记录配置并进行配置控制。(同上)
到 1976 年,Unix 支持体系已经建立,Unix 在公司内部成为唯一的产品。
1978 年 9 月,杰克·斯坎伦正在组建最初的计算机业务中心……我记得当时大概有五个人。我负责 Unix 系统,李·托马斯负责 MAC-8 微处理器芯片,尼克·马拉洛托负责为杰伊和迪克·哈顿开发一些软件支持工具……我相信还有一个完整的硬件中心负责 3B 的开发……我们试图打造一款能在当地广受欢迎的 Unix 系统……C 机器固然不错,但他们真正想要的是当时市场上最热门的 Unix 系统……3B 之所以能畅销,是因为它是当时最热门的 Unix 系统,这就是我们当时的想法。(同上)
3B 型机器主要在贝尔实验室内部使用,很少有机器流落到实验室之外。
1973年,首批Unix应用程序被安装在一个用于更新目录信息和拦截已更改号码呼叫的系统上。这是Unix首次被用于支持实际的、持续运营的业务。不久之后,Unix被用于贝尔实验室的操作系统自动化。它实现了监控自动化、测量功能,并帮助路由呼叫和确保通话质量。正如Tony Cuilwik所说:
这些系统执行的功能多种多样,包括网络性能测量、自动化网络测试、电路订单规划、电路订单记录、自动化故障检测、自动化或人工故障修复、服务质量保证、质量控制、库存控制、客户记录和客户计费,以及其他各种运营和管理功能。所有这些功能都需要能够实时向用户呈现数据。(摘自 Tony Cuilwik 的《接触 Unix 系统》,载于《Unix 评论》,1985 年 6 月,第 50 页。)
库伊尔维克曾任贝尔实验室运营系统开发部主管,后任俄亥俄州哥伦布市AT&T信息系统实验室主任。他指出,这些系统的目标是“确保人类能够做出最短的、可接受的响应时间。这一挑战是通过调整底层Unix系统来实现的。”(同上)最终,国家电信网络的基本完整性依赖于1000多个基于小型计算机的实时系统,而这些系统全部基于某种版本的Unix操作系统构建。
由于AT&T并不从事操作系统销售业务,Unix很快就以极低的价格提供给了学术机构。学术界,尤其是计算机科学界,对Unix表现出友好态度的原因有很多。约翰·斯通巴克列举了其中几个:
Unix之所以进入许多计算机科学系,主要是因为它是20世纪70年代中期大学能够负担得起的硬件(PDP-11)上唯一功能强大的交互式系统。此外,Unix本身也非常便宜。由于提供了源代码,它可以根据特定安装的需求进行定制。它的编程语言比汇编语言更具吸引力,而且规模小巧,便于个人学习和理解。(John Stoneback,“大学社区”,《Unix评论》,1985年10月,第27页。)
Stoneback 还讲述了 Unix 研究如何帮助学术计算机科学系建立和发展计算机科学研究。
Unix还有另一个吸引人的优点,许多人可能事后才意识到——它忠实地遵循了20世纪70年代中期盛行的软件设计和开发理念。Unix不仅证明了真正的软件可以像许多人所说的那样构建,而且还为当时正努力确立自身科学地位的计算机科学增添了可信度。教师们可以同时使用Unix并进行教学。在大多数方面,该系统都是优秀计算机科学的典范。它提供了简洁而强大的用户界面和工具,促进并鼓励了软件的开发。由于它是用C语言编写的,因此可以展示和讨论实际代码,并将教科书中的例子应用到现实世界中。显然,Unix注定会在学术界蓬勃发展。(同上,第27页)
Unix操作系统诞生之初就与学术机构非常契合。它不仅功能强大,而且还为教授们提供了一种教授新兴的计算机科学领域的模式。
Unix作为计算机科学研究领域的工具,其强大功能也得到了充分体现。研究人员以Unix为基础进行操作系统研究,主要受益于以下三个方面。首先,Unix的可移植性和灵活性使研究人员能够通过通用操作系统验证彼此的实验结果。其次,研究人员可以利用Unix提供的坚实系统软件基础,在前人工作的基础上进行拓展,无需从零开始开发所有组件,从而节省时间。第三,Unix允许在同一系统中同时进行研究和计算,使研究人员能够快速地将研究成果从实验室迁移到生产环境。这种速度对于尖端计算至关重要。
尽管AT&T以极低的成本向学术界提供了Unix系统,但学术界也以测试和贡献的方式回馈了Unix。例如,加州大学伯克利分校的Babaoglu和Porker创建了用于VAX计算机的Unix虚拟内存版本,后来由Bill Joy进行了优化。
在贝尔实验室,随着Unix系统被应用于实际应用,系统漏洞会被发现并报告给程序员。有时,使用Unix系统的各个部门也会为自身任务开发新的应用程序。研究实验室的职责是维护Unix系统,更新软件,并将发现的漏洞报告给程序员,同时分发修复程序。
1978年,贝尔实验室开始大量依赖Unix系统开展运营,Unix支持小组的重要性也随之凸显。这一趋势随着Unix 7版本的推出而愈发明显。当时,支持小组的目标是开发一个更加完善和稳定的Unix版本,同时确保系统稳定运行,从而保证贝尔实验室的各项工作顺利进行。Unix被用作贝尔运营公司众多支持系统的操作系统基础,贝尔实验室根本无法承受这些支持系统崩溃的后果。与此同时,在学术界,Unix用户需要自行维护系统。这催生了一个乐于互助的Unix用户社区。
UUCP随Unix 7版本一同推出,并由此开创了Usenet新闻组的发展先河。Usenet新闻组是ARPANET的升级版,因其为所有成员提供低成本的电子通信方式而受到学术界的热烈欢迎。Usenet催生了一个真正意义上的民主社区。这个社区不仅支持其成员,也反过来受到其服务对象的滋养。它乐于接受新思想,拥抱变革,并慷慨地分享其福利。1980年,计算机科学研究网络(CSNET)对学术机构进行的一项调查显示,超过90%的院系都使用一个或多个Unix系统。Usenet堪称Unix传播史上的一座里程碑,它以鲜明的色彩展现了Unix社区在广阔而充满活力的计算机世界中的团结。
Unix操作系统的流行源于其创新性,以及它使用高级语言高效编写,代码可根据个人喜好进行修改。Unix之所以在当时的操作系统中脱颖而出,关键在于其强大的软件工具、良好的可移植性、灵活性,以及简洁、紧凑和高效的特性。贝尔实验室在开发Unix的过程中,遵循了一系列由研究人员制定的指导原则。这些原则包括:
(i) 让每个程序都把一件事做好。要做一项新工作,就要从头开始构建。
而不是通过添加新功能来使旧程序变得复杂。
(ii) 预期每个程序的输出都将成为另一个尚未知晓的程序的输入。不要在输出中添加无关信息。避免使用严格的列式或二进制输入格式。不要强制要求交互式输入。
(iii)设计和构建软件(包括操作系统)时,应尽早进行测试,理想情况下最好在几周内完成。不要犹豫,舍弃不完善的部分,重新构建。
(iv)为了减轻编程任务的负担,即使需要绕道构建工具,并且预计在使用完毕后会丢弃其中一些工具,也应优先使用工具而不是不熟练的帮手。
(MD McIlroy、EN Pinson 和 BA Tague,“Unix 分时系统进展”,《贝尔系统技术期刊》,1988 年 7 月至 8 月,第 57 卷,第 6 期,第 2 部分,第 1902 页)
Unix 的神奇之处在于其创建系统时所秉持的理念,以及随后在贝尔实验室和学术界推广 Unix 的过程。虽然用短短一段话来概括 Unix 背后的核心理念并不恰当,但我们必须认识到,这种全新的计算理念具有革命性意义。它强调自由和个性化,兼具高效、灵活和多功能性,并在程序员和研究人员的世界中营造了一种开放的氛围和社群意识。Unix 操作系统在没有销售团队、没有市场营销团队、也没有硬件制造商支持的情况下,依然在全球范围内广受欢迎。这正是 Unix 的精髓所在。
从传播回归精神
J·格雷厄姆·斯宾塞
Unix 的传播和其精神演变是两个截然不同的故事,但两者之间却密不可分。Unix 的精神并非在它被推广到外部世界后就一成不变。传播在 Unix精神的演变中扮演了重要角色,因为 Unix 最终又回到了贝尔实验室。正如它被推广到外部世界一样,它也被带回了贝尔实验室。在这里,我们再次看到了那句不可或缺的 Unix 格言:“最后接触它的人拥有它。” 这句话或许是在贝尔实验室构建 Unix 时提出的,但它同样适用于传播的故事。例如,当伯克利系统设计公司在 20 世纪 70 年代末重新设计 Unix 内核时,其修改后的 Unix 版本又回到了贝尔实验室。由于伯克利是最后接触它的人,所以他们拥有了它。贝尔实验室团队肩负着解决新版本挑战和缺陷的重任。这些挑战不断推动贝尔实验室进行革新,迫使其进行创新。此外,这种创新不仅限于Unix本身的设计,实际上,它涵盖了整个Unix运行的架构。
那么,谁能讲述这些交织在一起的传播与精神的故事,讲述Unix如何走向世界,最终又回到贝尔实验室?谁能描述Unix如何建立起一个成熟的国际社区,并由此赢得创新和可移植性的声誉?这份声誉虽实至名归,但仍需进一步巩固。人们对Unix赞誉有加;历史学家马丁·坎贝尔-凯利和威廉·阿斯普雷在其著作《计算机》中指出,“Unix是二十世纪最伟大的设计杰作之一”(坎贝尔-凯利和阿斯普雷,222页)。令人惊讶的是,能够描述Unix环境持续革新的人选竟然是斯图·费尔德曼,他最为人熟知的身份是《Unix手册》的作者make。
费尔德曼是否有资格讲述这个故事,这一点并不显而易见。费尔德曼的背景以及他在Unix项目上的工作经历,并不能立即体现他对该项目的价值。费尔德曼在普林斯顿大学获得天体物理学学士学位,并于1973年在麻省理工学院获得应用数学和星系理论博士学位。长期以来,费尔德曼一直将计算机视为“业余爱好”,并声称他唯一与计算机相关的学术工作是在普林斯顿大学修读的一门研究生课程,以及在麻省理工学院参加西摩·帕普特关于自动机的研究生研讨会。费尔德曼的卓越才能为他赢得了在默里山(Murray Hill)的暑期工作机会,以及在贝尔实验室参与Multics项目的早期工作。费尔德曼罕见的兼具技术专长和相对缺乏经验的特点,往往使他在Unix的一些大型项目中处于边缘地位。这种介于内部人和外部人之间的视角,是审视Unix传播阶段及其精神演变的最佳切入点。毕竟,费尔德曼试图讲述的故事——精神*与传播之间的关系——不正是试图将内部与外部联系起来的经典案例吗?费尔德曼正是这种内部人和外部人的独特结合体,还有谁比他更适合尝试调和Unix的内部故事和外部故事呢?
费尔德曼对Unix项目的正式贡献包括Unixefl语言、第一个完整的f77编译器以及Unix。任何熟悉Unix开发者所面临的技术难题的人都应该立即意识到这些贡献对Unix本身构建的重要性。然而,这些贡献在Unix的传播历程中似乎远不如在Unix的构建历程中那样重要。但是,只有通过更深入的研究,才能真正认识到make费尔德曼贡献的价值。
make 是一个用于 Unix 的脚本,由 Feldman 设计,用于控制编译过程并生成可执行程序。Feldman 表示他的发明时间make 大约在 1976 年。在《用于微型计算机的 Unix 系统make》一书中,Ross Burgess 解释了在 Unix 编程环境中的价值。
如果您的程序包含多个不同的文件,您可能很难记住哪些文件包含在特定程序中,以及哪些文件最近发生了更改。例如,您可能正在开发多个程序,这些程序都使用您编写的各种通用子程序。或者,您可能有一个程序员团队,他们各自负责一套程序的不同方面。为了跟踪哪些文件需要在哪个程序中重新编译和链接,您可以使用该make实用程序。它可以跟踪哪些文件在哪个程序中需要,以及需要对它们进行哪些操作。通过记录各个文件的最后修改日期,您make 可以确定哪些文件需要重新处理才能生成完整程序的新版本(Burgess,194)。
make它会在文件中查找依赖关系,目的是更新文件并生成可执行程序。简而言之,make它是 Unix 的一个文书系统。听听 Feldman 如何make在更广阔的 Unix 视角下看待它,它既是系统的关键工具,也是系统本身的象征。
所以,make这一切之所以成为可能,是因为你可以问文件系统一个愚蠢的问题,它都会回答;如果你想运行一个命令,你只需运行命令即可。你不需要提前计划,不需要得到上帝的许可……你只需要去做就行了。因此,我几乎没怎么思考就把它组装起来了。
在《Unix生活》一书中,唐·利贝斯在其关于Make的章节前make,引用了理查德·E·费尔利的一句话:“系统的结构反映了构建它的组织的结构”(利贝斯,181页)。Make恰如其分地体现了Unix的一些基本组成部分。它make很简单;费尔德曼“不假思索”地就把它组装了出来。make它具有可移植性;贝尔实验室的众多工作人员在Unix项目中执行各种各样的任务时都使用过它。
事实证明,世界各地几乎所有Unix的下载都依赖于makeMakefile来管理和加速整个过程。新用户下载Unix时会使用一系列Makefile文件。这些文件是高效成功下载Unix的关键。Makefilemake本质上是Feldman设计的一个程序,用于控制编译过程并生成可执行程序。如果没有Makefile make,Unix用户就必须使用一系列程序,例如ccMakefile ld, as、yacc, lexMakefile、Makefilemv和cp, sedMakefile等ln,来重新构建复杂的软件集。简而言之,整个过程会变得更加混乱和低效。事实上,甚至可以说,如果没有Makefile make,Unix本身对潜在用户来说可能就不那么有吸引力了。如果没有Makefilemake来简化安装,Unix很可能会落后于其他操作系统。如果没有Makefile make,Unix虽然仍能保持一定的可移植性,但由此导致的安装效率低下对许多潜在用户来说就相当于缺乏可移植性。无论Unix的技术可移植性水平如何,潜在用户都可能无法承受安装的种种困难。
然而,就目前而言,make它依然保持着优雅的简洁性,其不可或缺性在每一次高效的Unix下载中都得到了应有的尊重。make持续的服务不断重申了Feldman对Unix传播的价值。它make从来都不是Unix传播的关键;只有Unix自身的设计特性才能称得上是关键。可移植性、相对的简洁性、自给自足性和友好的手册才是Unix赢得声誉的原因。它make并没有“推销”Unix,但它在帮助传播Unix声誉方面发挥了作用,成为了销售的推动者和传播的催化剂。
费尔德曼之所以更有资格反思Unix的传播,是因为他在伯克利大学待了一年,参与了具有里程碑意义的伯克利系统设计(BSD)项目。贝尔实验室当时并未意识到这款奇特的小型操作系统的全部潜力,便免费向教育机构提供Unix,只收取磁带成本。BSD是Unix在贝尔实验室之外的第一个重要分支。当然,我们不能说BSD是Unix在贝尔实验室之外的开拓创新精神的唯一功臣。早期BSD Unix的一系列版本之所以如此重要,是因为它向计算机界证明,这种创新精神同样可以在贝尔实验室的庇护环境之外蓬勃发展。BSD也为Unix在教育机构中奠定了坚实的基础,并帮助Unix与这些机构建立了至今仍然保持的紧密联系。
所以,我们在这里看到了makeUnix的创造者及其幕后推手。我们看到了Unix传播的意外催化剂,以及设计这一催化剂的人。他们能告诉我们关于Unix传播的哪些信息呢?费尔德曼的大部分内容都与贝尔实验室Unix精神的培育有关。秉承Unix的真正精神,费尔德曼似乎建议听众运用工具来理解Unix的历史。听众(或用户)有责任使用这些工具来扩展他们对Unix历史的了解。费尔德曼并没有罗列事实和日期,而是选择回忆Unix所散发的独特魅力,以及这种魅力如何转化为国际成功。
……如果非要说我做过的事情和我现在感兴趣的事情有什么技术方面的倾向,那就是如何利用一种技术来摆脱另一种技术带来的麻烦?(停顿)我曾不止一次说过,UNIX 最棒的地方之一就是它能让你摆脱它自己给你带来的麻烦。
如果说故障排除是 Unix 的标志,那么就很难忽视偶然发现对项目的重要性。
我给你讲一两个关于它的小故事,make让你了解一下当时的环境。它在本地使用了几个月后,就传播到了其他Unix系统上。Unix在公司内部已经零星地使用过。一楼技术支持团队有人上来,他们决定尝试用它make来支持系统版本发布。然后有人走进我的办公室说:“我这个Makefile文件出问题了。”然后他们就把这份1500页的Makefile文件扔到了我的桌子上……我当时就惊呆了。我说:“我的天,它居然能用!”当然,我之前用过的Unixmakefile代码最多也就15到100行。
费尔德曼在这里提出了一个关键的见解。他揭示了贯穿Unix精神的那种偶然发现和持续惊喜的感觉。在这段文字中,我们看到费尔德曼直到他自己编写的工具被投入使用、不断改进之后,才意识到它的全部功能。如果他连自己的工具的功能都不了解,又怎能知道整个Unix系统的功能呢?他又如何能评估这个新操作系统的全球前景呢?费尔德曼的这段经历在某种程度上是Unix传播过程的一个缩影。开发一个精巧的小工具并将其分发出去,却不了解它的真正功能,很快,这个工具就会被重新扔回你的办公桌上。随之而来的是一系列你从未发现的功能,以及一大堆需要解决的缺陷。
嗯,Unix 就像一间简陋的房子,或者说是一间布置简陋的房子。它缺乏专业操作系统那些豪华的便利功能。坏消息是,多年来,它不仅缺乏这些豪华功能,还积累了不少糟糕的操控性……它曾经……我不是汽车专家,但它在早期就像操作系统界的MG(小型汽车)。它功能齐全,足以让你从这里到达那里。用起来很有趣。它的操控性不如别克或凯迪拉克,性能也不如法拉利。但它很有趣。如果你想做什么,你就能做什么。然而,这种开放性也意味着,你脚下的系统随时可能发生变化。不止一次,凌晨两点,C编译器在我这个唯一用户面前崩溃了,因为丹尼斯也是个熬夜的人。
凌晨一点半,他可能还会安装一个小bug。他在这方面确实非常擅长。不止一次,我是第一个遭殃的人。而最好的答案是,两点半之前就能修复。这算是Unix的精神吧。我们当时生活在一个高风险、充满乐趣、瞬息万变的世界里。当然,自从十年前它成为正式产品,成为业界举足轻重的力量之后,情况就完全不同了。随之而来的是每年发布新版本和两年一次的bug修复带来的种种问题。Unix一直以来都用着世界上最愚蠢的加载器和相当糟糕的调试器……因为没人愿意去开发任何内在的东西。
事后看来,费尔德曼抓住了Unix精神的精髓,并将其与Unix的早期传播联系起来。费尔德曼,或者说任何人,都不太可能预料到Unix会取得如此巨大的全球性成功。当然,这种不确定性反而增添了贝尔实验室Unix项目“高风险、充满乐趣且瞬息万变”的特质。更重要的是,作为计算机领域的成功案例,Unix或许才刚刚起步。早在1995年,迈克·甘卡兹就在《Unix哲学》一书中大胆预测:“Unix成为世界操作系统只是时间问题”(甘卡兹,第19页)。费尔德曼可能会反驳这种说法:“Unix是一个卓越而简单的系统……但它终究是一个受时间限制的概念。”没有人能够真正断言Unix的时代是否即将终结,或者我们是否仅仅触及了冰山一角。我们可以肯定的是,只要 Unix 在计算机界传播开来,Unix 的持续革新就会继续下去,商标许可和故障排除什么的都见鬼去吧。
www.tuhs.org/Archive/Documentation/OralHistory