# 风格和工具

就在 Ritchie 和 Thompson 为 ACM 研讨会准备论文的同时，Brian Kernighan 和 P.J. Plauger 正在合作编写《程序设计风格要素》（*The Elements of Programming Style*）。Kernighan 曾说：“我们是在 1973 年写这本书的，并于 74 年初完成。”Plauger 评价道：

> Brian Kernighan 和我几乎是偶然地在 Murray Hill 的贝尔实验室获得了相邻的办公室……
>
> 我们一开始是为了共同感叹计算机编程的糟糕状况，结果却首次踏上了写书的道路，在大约四个月的时间里合著了这本小书。据我所知，这是“编程风格”首次被成年人以正式话题的形式公开讨论。
>
> 当然，这本书现在已经严重落伍了……

Kernighan 告诉 Peter Collinson：

> Plauger 和我一起写了那本风格书，结果相当不错，也很有趣。风格书的想法是收集大量程序并加以批评：这个写法不对，那个本可以写得更好。我们不是在教人怎么做，而是在告诉大家怎么不要做。当时主要是针对 FORTRAN 和 PL/I，那是在我们所面向的社区中占主导地位的语言。

《程序设计风格要素》引起了不小的轰动。但正如 Plauger 和 Kernighan 所说，它主要涉及的是 PL/I 和 FORTRAN。他们的下一次合作则更加通用，也更具影响力。Collinson 问 Kernighan 是如何参与《软件工具》（*《软件工具》*）一书的，他回答说：“很难说。”

> 几年后，我们觉得是时候告诉大家一些关于应该如何做事情的建议了。那时，我们对 Unix 环境的一些优势有了更清晰的认识：比如通过管道将程序连接起来，构建作为过滤器的工具。至于用什么语言写这本书，还不太确定。C 语言当然并没有在很多环境中普及。我之前已经写过 Ratfor（Rational FORTRAN）。Ratfor 由来已久，它仅仅借鉴了 C 语言的良好外观，但并没有带来更多的新东西。它很好地将 FORTRAN 转换成一种编程语言。
>
> 我们决定用 Ratfor 作为这本书的编程语言，这其实很不寻常，因为当时使用者非常少。我们这组人里几乎没人用 FORTRAN，除了那些担心可移植性的数值分析师，他们不想写出 Ratfor 那样难以阅读的 FORTRAN 代码。
>
> 原始版本是用 C 语言写的，并用了一点 yacc 语法（yacc 是 Steve Johnson 写的“又一个编译器生成器”）。以此为引导，用 Ratfor 编写的过程很快完成。然后它可以在只运行 FORTRAN 的机器上自举。《软件工具》软件包的一部分程序分发包括 Ratfor 用 Ratfor 编写的代码和 Ratfor 用 FORTRAN 编写的代码。磁带上的第一个文件就是用 FORTRAN 写的 Ratfor，这样你就可以直接拿出来开始运行。

Collinson 随后问道：“既然你们有了 Ratfor，接下来怎么做到《软件工具》呢？”

> 然后你坐下来思考，Unix 系统中哪些东西是有趣的。事实是，Unix 有大量非常小的工具，你可以用有趣的方式把它们组合起来。这引出了书中的前三章内容：字符输入和字符输出作为最基本的通用方式，文本就是一切，数据不过是一串文本行，也许再延伸到归档。
>
> 接着我们介绍正则表达式。这是 Unix 中一个非常重要的基础概念。基于它，接下来的内容包括模式搜索，比如 grep 系列工具，然后是编辑器。实际上，排序也是其中一款工具，你可以讲一些关于排序的有趣算法。
>
> 我们唯一做的其他事情是文本格式化，所以我们做了一款简单的格式化程序。最后，我们讲 Ratfor，说明这就是你一直在使用的程序，这就是 Ratfor 用 Ratfor 写成的。

《软件工具》附带了一套用 Ratfor 写成的磁带，这是专门为这本书编写的。但书是先出版的。Kernighan 评论道，

> Ratfor 独立于这本书，但它成为了这本书的载体。书中所述的版本比磁带上的版本更简单，因为通过完整实现的说明，你并不会学到什么新东西。像《软件工具》这样的组织纷纷成立，主要是在加州的劳伦斯伯克利实验室进行的。成员有 Debbie Scherrer、Joe Sventek 和 Dennis Hall 等人。他们成立了《软件工具》组织，并用它做了一些非常棒的事情，创建了“虚拟操作系统”等各种东西。多个机器间的巧妙技巧，全部以非常干净的方式完成。

回想一下 Unix 哲学：编写只做一件事且把它做好 的程序。这就是工具背后的理念，也是激励劳伦斯伯克利国家实验室那些人的理念。

> Debbie Scherrer 告诉我：
>
> “你知道，我最初是在 UOP（太平洋大学）开始的，但那里只有一门计算机课程。所以我转学到了伯克利。在我读硕士的时候，大约是在 1968 年，劳伦斯伯克利国家实验室有个工作机会。那真是太棒了。那时候有 Dennis Hall。Joe Sventek 在楼下的另一个完全不同的部门工作。他学的是物理，正在做一些秘密的与武器测试有关的事情……我们负责维护所有那些研究人员的系统，他们根本不关心计算机，只关心它能不能正常工作。但有一天，阿姆斯特丹自由大学的 Andy Tanenbaum 把一本书《软件工具》放在实验室的桌子上，他说：‘你可能会对这个感兴趣。’于是我读了这本书，觉得非常棒。就在 Andy Tanenbaum 提到这本工具书的时候，实验室里的 Dennis Hall 也发现了它。是 Dennis 把我拉进来了（当时我正做另一个项目），他是项目负责人，负责资金和指导我们，Joe 和我都听他的指挥。于是那个周末，我坐下来开始实现所有这些工具。那感觉真棒！Joe、Dennis 和我想，如果我们应该支持研究，那么这些工具就支持研究，于是我们实现了所有剩下的工具，还有其他一些东西。能源部的 Jim Poole 一直非常支持我们，给我们资金。其他人从来没明白这点，还在继续他们那些可怕的 FORTRAN 程序、扩展的 DCL 脚本和其他愚蠢的东西。”

事情发展得很快。

Mike O'Dell 告诉我：“记住，Debbie 认识 Brian，而他知道他们在做什么，所以他把那些询问工具的人引导到劳伦斯伯克利国家实验室。那就是用户组的起点。”要记住，《软件工具》不是关于 Unix 的，它关乎的是哲学和风格。Ritchie 说：

> 使用工具的方法既强大又在智力上节省资源，但需要一定的想象力去运用。相比构建一个更专门化的工具，组合更简单、更通用的工具可能成本更高。

有趣的是，Scherrer 和她的同事们意识到了工具概念的强大。他们很清楚这些软件工具几乎可以在所有可用的架构上运行。因此，Hall、Scherrer 和 Sventek 编写了一个虚拟操作系统（VOS），作为软件工具（用 Ratfor 编写）与运行的操作系统之间的伪接口。Scherrer 谦虚地说：“VOS 是 Dennis 的主意。”

我问了 Paula Hawthorn，她曾是 Mike O'Dell 在劳伦斯伯克利国家实验室的经理，关于那些工具，她告诉我：

> 当我加入劳伦斯伯克利国家实验室的计算机科学与数学系时，Debbie、Joe 和 Dennis Hall 已经完成了软件工具的几个版本发布，正处在“这到底算不算是真正的研究？”的争论之中。
>
> 问题在于，劳伦斯伯克利国家实验室本应专注于研究，那么我们怎么能说发布新版的软件工具真的是研究呢？“这到底算不算是真正的研究？”是那些想把研究成果变成实际可用系统的工程师们的最大难题，因为你为交付一款可用系统所做的很多工作并不一定是研究，但如果没有经过实际应用测试，研究本身又完全无效。所以，我对那段时间的记忆都被“这到底算不算是真正的研究？”的争论所浸染，还有“既然需要用 Unix，为什么不直接用 Unix？”的争吵。大致来说，软件工具看起来只是为了让非 Unix 系统更像 Unix 而做的权宜之计。这也引发了激烈的讨论……

与几位其他人沟通关于这些工具的问题后，软件工具用户组（Software Tools User Group，简称 STUG）于 1978 年成立。关于 VOS 的文章发表于 1980 年 9 月的《ACM 通讯》杂志，但 STUG 的一次会议早在 6 月 16 日就已经召开，那次会议是在特拉华大学举办的 USENIX 会议之前。Wally Wedel 在《软件工具通讯》（第 4 期，1980 年 10 月）——这是最初由劳伦斯伯克利国家实验室发行的一份不定期通讯——中报道了此次会议。软件工具已经可以用于多个 DEC 操作系统、Control Data Cyber、TSO 环境下的 IBM 系统，以及运行在 MPX 1.3（MPX 是一种原始操作系统）的 SEL 32/77 上（NASA 的 Ames 研究中心未能在其上实现 shell，尽管他们让所有工具都能工作，等等）。到了 1981 年 11 月期刊，Phil Scherrer（曾在 Unicorn Systems 工作，现任职于斯坦福大学）能够报道：

> 软件工具现已完全移植到微型计算机环境中。选择了运行于 8080、Z80（Zilog 商标）和 8085 处理器上的 CP/M 操作系统（Digital Research 商标），因为该系统在硬件配置（勉强）足够的设备上广泛可用……
>
> STUG 发行磁带上的所有工具，以及《ACM 通讯》文章中指定的许多扩展，都已被成功移植并运行良好。

同期的《软件工具通讯》列出了近三十种实现了这些工具的架构，以及实现者的姓名和地址。制造商按字母顺序从 Burroughs 到 Zilog 不等；机器规模则从 Z80/8080（64k 字节程序内存）到 IBM 370 和 DEC 20。地理位置上，实现者遍布全球：从日本川崎，经美国和加拿大，到英国和荷兰埃因霍温。

工具变得重要的地点之一是佐治亚理工学院。Gene Spafford 曾在那里工作很长时间（虽然不是从最初开始），他告诉我：

> 在七十年代中后期，佐治亚理工学院的人员拥有几台运行 Unix 的 PDP-11 机器。这些机器既用于研究，也作为医学数据库研究项目的一部分。
>
> 许多学生和教职工都迷上了 Unix，想要把它移植到系里主要的研究计算机上，这些计算机是 Prime 机。那时，Prime 机确实是很不错的机器，拥有虚拟内存、良好的多用户能力以及许多其他优良特性。不幸的是，Prime 架构并不是一个容易写操作系统的机器，Unix 不可能直接移植到这些机器上。
>
> 作为额外的诱因，最后剩下的一台 PDP-11 被一位 DEC 现场工程师“炸毁”了——他把电源装反了，导致 110 伏交流电灌进了背板。DEC 始终未对此事做出补救，所以我们失去了 Unix……
>
> 学生们随后编写了一款系统，但佐治亚理工不允许将该系统免费发放，因此它被授权给那些愿意付费的大学和公司使用。曾经有很多地方在运行它。Prime 机甚至对其进行了市场推广。几年后，有三件事导致它的消亡：
>
> * Prime 公司的一些人不满客户更喜欢《软件工具》的界面胜过 Primos，因此他们停止对《软件工具》团队提供特别支持。Prime 工程部门的许多“支持者”离开，组建了 Apollo 公司。留下来的人则将部分《软件工具》的理念整合进了 Primos，转而背弃了佐治亚理工的开发团队。
> * 《软件工具》团队为系统编写了一个非常好的 C 语言编译器和库。他们希望全面切换到 C 语言并成立独立公司提供支持。不幸的是，佐治亚理工的管理层因编译器及相关代码的所有权问题产生小气纠纷，导致整个团队集体退出，《软件工具》实际上失去了进一步支持。
> * 随后，VAX 机器大量出货，并配备了 BSD Unix。以前使用《软件工具》的用户现在可以用相同或更低的成本获得真正的 Unix 和虚拟内存。需求迅速下降。
>
> 主要参与者有 Dan Forsyth、Paul Manno、Perry Flinn、Allen Akin 和 Win Strickland。

Spafford 的提示让我找到了 Manno 和 Forsyth。Forsyth 在与他以前的同事们聚集讨论以确保准确性后告诉我：

> 佐治亚理工学院信息与计算机科学学院的软件工具项目始于 1976 年几起独立事件的结果。首先是《软件工具》一书的出版。其次是军方对可移植 COBOL 的兴趣。最后，更贴近实际的是，一群大四学生暑假回来后发现，他们心爱的 Burroughs B5500 因维护资金不足而被停用，所有 PDP-11 机器也被封闭，以保护机密的医学研究数据。取代他们此前理想的计算环境（主要由军方的研究项目资助）的是一台崭新的 Prime 400。
>
> 由于多种原因，UNIX 的移植根本不可能，包括无法获得用于移植的 PDP-11 机器、Prime 内部结构起初缺乏文档，以及缺乏教师的兴趣。与此同时，当地的编程环境是一种介于 GE-645 和后来成为 Intel 80286 的架构之间的机器，配有 FORTRAN-66 编译器，以及一个分时操作系统，该系统在最佳情况下只能接受由两个六字符文件名和十个八进制数字组成的命令！
>
> Philip H. Enslow 博士（陆军研究项目的负责人，同时很快成为许多学生的指导教师）建议的一个高级设计项目是将 Ratfor 移植到 Prime 上。这显然是在我们任何人知道 Brian（Kernighan）和 Bill（Plauger）做得多么出色之前。我们从 Addison-Wesley 得到了磁带，Ratfor 很快就运行起来了。
>
> Allen Akin、Perry Flinn 和 Jack Waugh 开始意识到这些工具的潜在用途。1977 年初，Primos 的命令行界面被认为完全不适合优雅地连接这些工具，因此临时拼凑了一个简单的类似 UNIX 的 shell。随后不久，Paul Manno 和我也加入了这项工作。
>
> 尽管大家都渴望创建一个优雅的计算环境，但我们每个人主要还是专注于其他项目。不过，我们经常发现，遵循 K\&P 的建议去扩展或新增工具，能够比每次从零开始更高效地完成项目工作。在这种激励下，《软件工具》子系统开始迅速发展。由于这是一个更有效的环境，其他学生和教师的使用也开始增加。我们收到了许多其他研究人员的贡献，同时也发现有必要建立文档标准，并编写大量文档，以避免花费太多时间回答问题。当然，我们还必须扩展文本格式化器和其他工具来实现这些需求。
>
> 到了 1978 年夏天，我们已经拥有了一款能够有效替代 Primos 命令和编程环境的系统。除了最初的《软件工具》，我们还拥有了大型子程序库、基础 shell、扩展版 Ratfor、电子邮件、公告栏、全屏编辑器以及许多其他新工具。
>
> 在 Phil Enslow 和 Prime 计算机研究主管 David Nelson 的努力推动下，Prime 公司的研究部门也开始对我们的工作产生兴趣。那年夏天，在 Georgia Tech 和 Prime 的协助下，Allen、Perry 和我访问了 Prime 研究部门，并获得了开发“高级”命令解释器的灵感。我们开始将 Multics、V6 UNIX、RDOS 和其他系统的特性结合成一个统一的命令语言。《软件工具》、Unix 和 Algol 68 为我们树立了榜样，激励我们追求优雅、正交性和可重用性的目标。
>
> 到了 1979 年初，我们已经开发出了“新 shell”，回头来看，它在外观上很像 Bourne shell（尽管我们当时从未见过它）。这个 shell 包含了几个有趣的概念：多个标准输入和输出，以及用于连接工具有向图的语法；任意长度的命令行；由外部命令管理的控制结构；以及作为对象处理的作用域变量，其执行结果会在标准输出上输出其值。
>
> Prime Research 获得了这个被亲切称为 Subsystem 的系统副本，并在内部提供使用，因为它在文本处理和研究编程方面更为出色。大概同期，我们与 Prime 的工程团队建立了一个不太理想的关系。似乎我们总能在 Prime 工程团队宣称某项任务不可能或不切实际的几乎同一时间，成功实现并发布这些功能，尤其是那些改善操作系统接口的功能。当然，我们享受着安装用户少且不必考虑向后兼容的优势。不管出于什么原因，我们的工作对后续 Primos 版本的影响只是间接的。
>
> 随着更多 Prime 系统的引进和一种名为“ethernet”的新型终端连接方式，《软件工具》Subsystem 成为了 ICS 学院的管理纽带。它处理本地电子邮件和部门的文本处理任务，并为许多研究生（包括我自己）提供了可以直接提交的高质量论文，免去了找打字员的麻烦。乔治亚理工的高层决定不公开发布我们的成果，而是收取许可费。即使当时高达 3,000 美元的天价许可费，许多 Prime 站点仍从全球范围内获得了几十份授权，包括英国、德国和澳大利亚。
>
> 1980 年，来自劳伦斯伯克利国家实验室的 Debbie Scherrer 邀请我们参加在多伦多举行的 USENIX 会议期间的《软件工具》用户组会议。乔治亚理工协助我们飞往多伦多，我们发现自己被许多新思想包围。这些会议极具吸引力，让我们接触到了在我们那个封闭的院系环境中难以想象的新视角。我们能向用户组贡献一些软件，但由于许可限制，我们从未能发布“新 shell”及更有趣的工具。
>
> 到 1981 年，当 Allen、Perry 和我离开时，Subsystem 已经拥有了完全重写的 Ratfor 预处理器、一个语法解析生成器、一个与语言无关的代码生成器和一个 C 语言编译器（用 Ratfor 写的！），以及数千页的文档。项目由 Jeanette Myers、Terry Countryman、Peter Wan、Scott Lee 和 Arnold Robbins 接手并管理得很好。在此期间，AT\&T 开始提供低价的 Unix 二进制授权。一年内，Unix 机器的价格降到了 Prime 或 PDP-11 的五分之一。不久，Unix、vi 和 troff 普及到大众手中，Subsystem 的商业需求开始减少。
>
> 在乔治亚理工，4.1BSD Unix VAX 机、AT\&T 3B 系列和 Sun 3 系列像杂草一样大量涌现，这让中央计算管理者非常头痛。CSNet、NSFnet 和 USENET 使得 Unix 计算资源成为参与不断增长的互联网社区的必要条件。Subsystem 于 1985 年发布了最后一个版本，代码被置于公共领域。不久之后，Subsystem 和 Prime 机一起退出了本地使用，理所当然地被促使其诞生的软件所取代。

《软件工具》引发了另一场草根运动。另一批狂热用户，虽然与 Unix 用户部分重叠，但哲学是可移植的：编写只做一件事且做得好的程序。

许多参与 STUG 的名字对 Unix 用户来说也很熟悉：Neil Groundwater、Mike O'Dell、Scherrers、Joe Sventek、Dave Stoffel 和 Wally Wedel。

我上次提到 O'Dell 时，他还是俄克拉荷马大学的本科生。现在他已经完成了硕士论文（“我前一阵子又看了看，”他说，“并不太尴尬。”），正在找工作。他的话是：

> 我离去 Murray Hill 的 1127 研究组工作只有两周时间了。我去面试了。然后就是一场“死亡行军”，文件在一张桌子传到另一张桌子，正好赶上某人离开去度两周假期。所以本应是两周的审批流程……却拖成了两个月。期间，我去了位于博尔德的 USENIX 一月会议，参加了《软件工具》会议。我一直对《软件工具》感兴趣，想通过它把有趣的东西带到 IBM 机器上，而当时我们还在努力争取（让俄克拉荷马买一台 DEC 机器）。所以我去了《软件工具》会议，Debbie Scherrer 发言，讲了他们做的所有精彩工作，演讲结束时她说：“哦，顺便说一下，我们正在找人来管理我们的 Unix 系统。”我几乎是爬过人群的，我记得会议快结束时我真的把椅子扔到一边，就冲上去。实验室那边来了六个人——Joe Sventek、Peter Krebs、Debbie、Dennis Hall，Roland Johnson 可能也在。面试流程是跟这六个人一起吃午饭，他们一边吃中餐，一边跟你聊——交替轮流面试。
>
> 总之，我回家后他们给我买了机票，我做了个关于我的论文的报告，他们给了我一次工作邀约。于是我面临一个糟糕的抉择，要在劳伦斯伯克利国家实验室和贝尔电话实验室之间选。贝尔电话实验室一直拖拖拉拉，最后劳伦斯伯克利国家实验室说他们必须得到一个决定。于是我打电话给 Dennis \[Ritchie]……他告诉我应该接受另一个工作。

于是 O'Dell 去了劳伦斯伯克利国家实验室，成为了 Unix 大师、ARPANET 联络人（11/70 是早期的 ARPANET 主机），以及其他几个角色。Neil Groundwater 也参加了那个 Boulder 会议，他也参与了 STUG：

> 我是在 1980 年的 Boulder USENIX 会议上熟悉了 STUG。大约在那个时候，劳伦斯伯克利国家实验室（Sventek、Scherrer 等人）完成了 90% 的工具和工作，但其他人也开始“使用源码”（工具）。
>
> 我们参与了为美国海军提供咨询的几个项目，这些项目有不同的编程环境。我们建议使用这些工具，作为他们在多个平台上控制构建环境的方法，但结果发现他们主要是在 VAX/VMS 上使用它。
>
> 我最大的贡献是一款文本控制系统（Unix 爱好者称之为 SCCS），它实现了文本文件版本控制的创建（create）、差异（delta）、获取（get）和编辑（edit）功能。该系统基于 J. W. Hunt 和 Doug McIlroy 发表在贝尔实验室技术备忘录中的 diff 算法。

STUG 正式在那次博尔德会议上成立。Groundwater 被选为首届董事会成员，而 O'Dell 则搬到了伯克利。

Debbie 和我在实验室共用办公室三年。她是这个世界上最可爱的人，拥有的精力超过任意六个人的总和。《软件工具》的热度达到顶峰后趋于平稳。遗憾的是，Unix 社区从未真正学到《软件工具》那些人传授的经验。我认为，《软件工具》的团队对可移植性的理解无人能及，而 Unix 社区因此失去了很多。Unix 的问题在于写代码太容易了，人们看不到不去写的理由。这并不是一种通过痛苦获得救赎的说法。《软件工具》里的许多东西之所以运作得更好，是因为他们真的做对了，而不是让 5,700 个人去重复造轮子。

工具的理念早已超越了 Unix 的领域，蓬勃发展。

![《软件工具》](/files/Iud3gfioB5v20x9WOlu6)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.bsdcn.org/unix-si-fen-zhi-yi-shi-ji/shi-shen-me-rang-unix-cheng-wei-unix/12-style_and_tools.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
