# 实用工具

无论 Unix 的版本或厂商如何，每次安装都会附带大量程序。这些程序包括编辑器、格式化工具、编译器；还有一些实用工具，能让用户按字母顺序排列列表，跟踪程序或文档的不同版本，甚至“接触并交流”其他用户。本章将聚焦其中少数几个：一些非常早期的工具——troff、eqn、tbl、yacc、mail、make、awk——以及一些较新的工具——UUCP、TCP/IP。后两者催生了更多实用程序（Mike Muuss 的 ping 和 Earl Cohen 的 finger 是很好的例子），也孕育出一个全球范围内几乎即时“交谈”的用户社区。这个社区对 Unix 至关重要。问题、解决方案、程序、抱怨、公告等都可以自由交流。正如 John Quarterman 所指出的，这个网络用户社区规模估计有三千到三千五百万人，相当于一个比加拿大还大的国家。

Mail 在第一版就已经存在，roff 和 ed 也是如此。Morris 将 roff 移植到 635 计算机上之后，McIlroy 用 BCPL 重写了它，随后 Thompson 将其引入了 Unix。但后来 Joe Ossanna 将 roff 推进发展成了 troff，一个真正用于排版文档的格式化工具。Ossanna 于 1977 年 11 月 28 日去世，但 McIlroy 告诉我：

> Joe 是军需官。他走访各个供应商，关注硬件的新动态，处理工厂部门的各种事务，等等。他是严肃却可爱。

eqn 出现在第五版。Brian Kernighan 曾说这是他对 Unix 的第一个重要贡献。正如他对 Collinson 所说：

> 这些程序当时都是用汇编语言写的。最初版本的 troff，大约是在一九七三年或一九七二年底写成的，是一个汇编语言程序，专门为 Graphics Systems 的排版机设计。直到今天，troff 语言语法中仍然保留着那个古老机器的痕迹。
>
> Joe Ossanna 把它转换成了 C 语言，我想是在很大压力下进行的，他其实并不想把它转成 C 语言。他于一九七七年末去世，我“事实继承”了它，尽管直到大约一年半之后我才尝试编译它。我开始着手让它独立于 Graphics Systems 的排版机，因为那台机器当时明显已是日薄西山。我开始加入图形功能，因为新的排版机——Mergenthaler 机器，具备一定的图形能力。你可以非常精确地定位点，从而画出线条和曲线。
>
> Mike Lesk 大约在一九七五年写了 tbl。Lorinda Cherry 和我很快写了 eqn。\[Cherry 告诉我她是项目发起人，Kernighan 后来“加入”了；但 Kernighan 因其极为成功的语法设计而被认可。] eqn 是第一个文档准备预处理器。这种设计其实是被逼出来的，俗话说“需求是发明之母”——类似的原因。troff 已经非常接近 PDP-11/40 的地址空间极限了，而且是用汇编语言写的。我从没学过 PDP-11 的汇编语言，我想 Honeyweil 机器是我学汇编语言的最后一代机器。
>
> Joe 非常珍视 troff，他很乐意帮忙修改让它实现功能，但它是他的程序，他不会允许别人随便修改。所有这些因素使得 Lorinda 和我几乎被迫写一个单独的程序。
>
> 多种因素的汇聚使得这项工作进展得相当顺利。首先是 C 语言刚刚变得相当实用。其次是 yacc 解析器生成器刚刚问世，还有管道机制也刚刚被发明。所有这些因素加在一起，使得以这种方式开展工作成为可行的方案。

Kernighan 和 Cherry 合著的《A System for Typesetting Mathematics》发表于 1975 年 3 月的 *CACM*（《计算机协会通讯》）。M. E. Lesk 撰写的《TBL - A Program to Format Tables》是贝尔实验室的计算机科学技术报告第 49 号，日期为 1976 年 9 月 14 日。这两种预处理器与 troff 配合，使 Unix 用户能够排版各种复杂文档。而各种宏包的拓展（用于补充 -mm“备忘录”宏）更进一步扩展了这些功能。Mike Lesk 编写了 -ms，Eric Allman 编写了 -me 宏；其中只有 -ms 出现在 Unix 的 Research 版本中，-mm 出现在 System III 和 System V 中；-me 和 -ms 则出现在 BSD 中。（Lesk 还编写了 refer，这是一种使用参考文献数据库来提供参考文献与脚注的程序。）

yacc（Yet Another Compiler-Compiler）是 Steve Johnson 的创作。他在贝尔电话实验室（Bell Telephone Laboratories）工作的时间远早于 Unix 的诞生：

> 我 1963 年第一次在贝尔实验室担任暑期工作。我一直对计算机感兴趣，在拿到学士学位之后，曾考虑过读研究生。可我能去的地方屈指可数，而且大多是电机工程（EE）系，在那里我得去上电厂构造之类的课程，而我对这些完全不感兴趣。于是我决定继续念数学。所以我在 1963 年暑假去了贝尔实验室。我的第一位上司是 Tom Crowley……他们有个规定，基本上就是你不能连续两个暑假为同一个小组工作。所以下一个暑假我就去了数学组，做 ALPAC 项目。再下一个暑假，我则算是“把实习项目补齐”，去了人类信息处理小组，那是一个很棒的团队，由声学家、语言学家和心理学家组成——他们做实验设计和数据分析。他们刚做完一些关于多维尺度分析（multidimensional scaling）的研究，这启发了我写出第一篇论文，关于聚类的。这篇论文被引用的次数比我之后发表的任何其他论文都多——有七百多次。
>
> 我完成论文后就来到贝尔实验室，我可以自己选择想加入哪个小组。我选择了人类信息处理小组，因为他们当时正在做一些我感兴趣的计算机音乐相关工作。在那里我做了各种各样的事情。当时，Multics 被号称是解决高强度计算的终极方案，但它其实是个灾难。我们基本上把 7094 搬到了 Indian Hill 实验室，而此时根本没有可用的计算机系统，只有那台 645 上的 GECOS。它号称可以支持 1000 个用户，但实际上连一个用户都几乎应付不过来。（McIlroy 向我指出，645“做了不少批处理”。）
>
> 所以，大约在工作一年后，为了能让这几百万美元的硬件真正跑上一些 FORTRAN 程序，我在走投无路之下，同意去协助推动 timesharing（分时系统）。于是，在 1969 年，我真正去和计算中心以及一个小组一起工作。那时候，计算中心是由计算机科学研究实验室负责运营的。而与此同时，还有一群文员、计算机操作员、打卡员等等，他们则隶属于研究部门。我在那里待了一年左右之后，他们终于建立了一个组织，来专门负责运营计算中心，这个决定其实早该做了。我决定还是留在研究部门，也正是通过这条“后门”，我加入了那个开发 Unix 的小组。
>
> 我最初是和 Dennis Ritchie 一起合作另一个计算机代数系统，叫做 Altran；Dennis 为 Altran 语言写了编译器。那是一个用 FORTRAN 写的递归下降编译器，绝对是一项惊人的壮举——就像用牙签盖摩天大楼。他还为一种叫做 B 的简单语言写过一个编译器，它运行在 Honeywell 系统上——我们曾用它写过一些系统程序。但当他和 Ken 开始开发 Unix 的时候，他就放弃了他那套 B 编译器，而我则算是把它接手了。我想在这个语言中加入一些我需要的功能，比如我加了异或运算符（exclusive OR）。我从和 Dennis 一起工作、从研究他那真正优秀的作品中学到了非常多关于编译器的知识。我也因此相信了一个理念：你可以通过阅读他人的代码学到很多东西。就像在阅读一部杰作、一部伟大的著作。
>
> 嗯，当我想加这个功能的时候，我去找了 Al Aho，因为我听说他对处理表达式的新方法很感兴趣。那场面真是挺有趣的。Al 一直点头，说：“是的，我读过 Knuth 的那篇论文，那是个更好的方法。”于是我们为 B 语言的表达式拟了一套简单的语法，他一直说：“我来给你做个解析表。”不过这事拖了几次。最后，他跑到仓库去，拿了他们能找到的最大一张纸，大概有两英尺见方，铺在桌子上，然后把它划分成一个个小格子。然后他开始对着它念念有词，嘴里嘀咕着，边嘀咕边在格子里写一些小符号。我站在一边看了一会儿，他说：“你干点别的去吧，等我弄好了叫你。”所以我走开了，每隔几个小时回来一次，他还在那纸上嘀咕着、写着。终于，第一天快结束时，他说：“我明天把它收尾。”第二天，他终于说：“好了，搞定了。”然后把那张纸递给我。我说：“我拿这个干什么？”
>
> 于是他教我怎么写解析器，我们把那张表输进了系统。我们成功解析了几个表达式，然后又解析了另一个表达式，结果错了——表里有个 bug。Al 说：“哦，不！”然后他又花了两三个小时擦掉重写。我们把新表输进去，修复了那个 bug，结果又出现了另一个 bug。于是我说：“Al，你干脆告诉我你到底在做什么吧？”他说：“好吧，其实真的不难。”然后他就教我如何构建那张表。我听完就说：“哦，那我可以写个程序来干这个。”他说：“真的？”——这就是 yacc 的诞生过程。

Johnson 还编写了第一个可移植的 C 编译器、lint、spell，并与 Dennis Ritchie 一起完成了向 Interdata 8/32 的移植（1977/78 年）。lint 是一个 C 程序检查器。它是一个实用的程序，可以检测 C 程序文件中可能是 bug、不具可移植性或浪费的特性。spell 是一个拼写检查器。它从指定的文件中收集单词，并在拼写列表中查找它们。那些既不出现在拼写列表中、也无法从拼写列表中的单词派生出来的单词，会被输出到标准输出。spell 并不是第一个拼写检查器。这个荣誉属于 Bob Morris 和 Lorinda Cherry，他们编写了 typo。它出现在 Version 3 到 Version 7 中。spell 首次出现在 V5。用 Steve Johnson 的话来说，typo：

> 就是从来抓不到我的拼写错误。我拼写是非常依赖发音的，经常把 -ible 和 -able、-ance 和 -ence 搞错，而 typo 从来没能发现这些。它是基于三字母组（trigram）的统计，而我的错误恰好都在那些统计中出现过。但 typo 在找出像“th 少了一个 e”这样的错误时非常擅长。它会根据某个拼写组合出现的可能性有多小来对结果排序。

Johnson 的 spell 实际上是基于一个词表的，用户可以自行扩展这个词表。

> 他告诉我，
>
> 1973 年一月到九月，我去滑铁卢大学休了一个学术假期，和 Morven Gentleman（现在在加拿大国家研究委员会工作）一起做一些研究。Morven 曾参与过最初的 ALPAC 系统，对计算机代数很感兴趣——我们曾经合作过——他是一个非常有意思的研究伙伴。那段时间我离开正是一个尴尬的时期。C 语言正是在我离开的期间发明的。当我回来时，yacc 已经被别人从 B 语言翻译成了 C 语言。还有第一个所谓的可移植 C 编译器，也是由同一个麻省理工合作学生 Alan Snyder 完成的。这是一次非常有启发性的尝试，包含了许多很好的想法，但由于 PDP-11 内存容量有限，它是一个四遍编译器。每一遍编译的大部分时间都花在读取上一遍的结果和写入下一遍的结果上，几乎没有时间做实际的工作，因此效率极低。
>
> 所以它非常慢，这和那个编译速度很快的旧 B 编译器形成了鲜明对比。Al 曾经让它在 Honeywell 机器上勉强运行，但里面还有很多 bug。好吧，他大约在我从加拿大回来时回到了麻省理工学院，于是我接手了这个项目。我的老板 \[Elliott Pinson] 强烈建议我接管它。于是我开始修复代码生成器中的 bug，发现很多问题其实是 Al 当初设计方式固有的。你知道，那时候的代码生成器采用我称之为“woopsie”方法：你假设有足够的寄存器，所有东西都会放到正确的位置；一旦出现问题，你就说“woopsie”，然后开始寻找可以暂存到内存的东西。大多数时候，这样生成的代码还算不错，但遇到糟糕情况时，结果简直惨不忍睹……
>
> 我当时正向 Al Aho 抱怨这些问题，这些对话促成了我认为自己在理论方面最优秀的技术成果——一种用于生成表达式代码的算法。它能够保证生成最优代码……Al 和我，还有 Jeff Ullman 一起完成了一些非常有趣的工作。对我来说，最终的结果是对代码生成有了更深刻的理解。
>
> 与此同时，我们给 PDP-11 增加了更多内存，这使我能够拿回一些 Al Snyder 的程序并重新组合。不久之后，我几乎重写了整个程序。虽然保留了一点 Al 的语法，但基本没有他的代码了。这个编译器就是我称之为的可移植 C 编译器——pcc，最初是为 Honeywell 设计的。稍后我们觉得将它移植到 IBM 也是不错的主意，所以我通过修改 Honeywell 编译器写了一个 360 版本。再过一段时间，有一台叫做 3A 的交换机，我也为它写了一个编译器。在这个过程中，我意识到为这三台机器做的很多工作是相同的；于是我花时间把这三种编译器合并，发现 90% 的代码是相同的。于是我在脑海里构建了一个流程，用来处理那剩下的 10%……
>
> lint 是个有趣的故事。当我决定真正写一个可移植的编译器，把我手头这三套东西做得真正可移植时，我知道如何处理前端，但代码生成器对我来说依然是个谜……所以我有了一个需要测试的前端，却没有办法去测试它。于是我想，也许我能用前端做点有用的事情，如果它确实有用，或许别人会在他们的代码上运行它，帮我调试。那么什么是有用的呢？前端应该是在解析函数……我想到一个常见的编码错误是函数调用时参数数量写错，事实上，函数到底在哪里有时候也不容易确定。所以我写了一个程序，它会读取你的文件，首先告诉你函数在哪里。后来我意识到它还能做调用之间的参数检查。lint 真正是我用来调试编译器前端的工具。这也解释了很多，因为它后来在许多组织里成了“公共道德的守护者”。
>
> 你知道，当我们在 1977 年第一次移植 Unix 时，遇到了一个非常严重的问题：许多人编写的代码里，是直接从手册里抄录结构声明的。正是在那个时候，我们引入了头文件的概念，认为它们应该因机器而异。我们希望确保 Unix 程序都使用头文件，尤其是操作系统自己使用的那些头文件。于是，lint 很早就学会了检查头文件的一致性……这使得我们能够在几周内审查大量代码——第六版 Unix，清理掉不一致的地方。这也帮助我们把这些代码整理成 V7 工具集（V7 是第一个可移植的系统）。

克制住想谈论 Unix 中所有内容的冲动，我先简单说说 awk，然后再谈通信。Peter Collinson 曾问过 Brian Kernighan 关于 awk 的事：

> awk 大概起始于 1977 年。这是我参与过的最大的软件项目，规模之大让我至今难忘。项目组只有三个人，而三人合作其实非常困难。两个人合作会容易得多，因为三个人分工更难，意见分歧也更多。有时这挺好，能带来更多不同的想法，但有时候却让项目不够统一。不过，和 Al Aho 以及 Peter Weinberger 一起工作非常愉快，我对此毫无问题。
>
> 有三条不同的思路汇聚到一起。我的部分是基于当时实验室的 Mark Rochkind 写的一个工具。这个工具本质上是一个数据验证工具，它接受一对正则表达式和相应的消息。它扫描输入文件，如果发现匹配某个正则表达式的内容，就会打印出对应的消息。当然，他用 C 语言写了这个工具，编译后变成了一个识别器。这个想法非常巧妙。
>
> 从某种意义上说，这就是 awk 的基本理念：有一组模式，每个模式对应一项要执行的操作。并不是说以前没有类似的程序，但这是一个非常清晰的例子。此外，我也玩过很多可编程编辑器。我们经历过一段 qed 流行的时期。qed 是一种糟糕透顶的编程语言，但人们还是用它。
>
> 这是一个具有多缓冲区和多文件功能的行编辑器，非常类似于现在的 emacs。
>
> 我一直在想，肯定有更好的文本处理方式。我想要的，是能够同时操作文本和数字的工具。
>
> Al Aho 是正则表达式领域的世界专家。Peter Weinberger 在与数据库相关的领域有深厚背景，他对类似数据库的东西很感兴趣。awk 并不是一个数据库工具，但它确实带有那种数据库的味道。于是，我们将这些杂糅的想法结合起来，创造出了这个东西。
>
> 它最初的设计本意是用来编写这些一行或两行的小程序。确实如此。我认为它非常吸引人，因为它自动完成了许多事情。它能顺畅地处理字符串和数字。它是一个解释器，没有任何负担，也没有生成中间目标文件。人们开始写一两行的小程序，结果程序慢慢变得越来越大；有些甚至大到难以置信，达到数万行——这完全没有意义。
>
> awk 始终在背后进行着缓慢的改进。有一次，我又回到了我最初的想法——我真正想要的是一种编程语言，能够像大多数编程语言处理数字那样轻松地操作文本。我认为，与其像 C 从 B 发展那样走一条路，不如走另一条方向。
>
> 我发明了一种叫做 A 的语言，非常简单，它把 awk 的基本概念包装进了一种编程语言里。它运行得不是很好。比如它确实有函数，但没有任何隐式输入或输出之类的东西。我玩过一阵子，但它从未真正好用，实现在很多方面都很不稳定，所以我自己用得也不多，别人也几乎没人用。
>
> 现在市面上有几个其他版本的 awk，特别是 GNU 版本叫做 gawk。它和我们的实现非常接近。在开发过程中，我们和他们保持了大量联系，尽量让各个版本保持同步。还有 DOS 版本，我比较熟悉的是 MKS 版本；它同样和我们实现得很接近。最后还有 POSIX 标准化的 awk，目前还处于草案阶段。
>
> 这差不多就是我们写进书里的内容。我觉得大致就是这样。不过标准化过程中有一些细节上的争议，我想这是必要的。有些地方和书里的内容有冲突，比如状态变量在从数字转为字符串或从字符串转为数字时的处理方式。这类细节可能没有被充分明确说明。
>
> POSIX 在至少几个方面采取了一个观点，而我们则持另一个看法。总体来说，我觉得大家对主要的核心内容还是达成了一致。

邮件功能在 Unix 最早的版本中就已经存在，手册页上将“owner”（所有者）列为 Ken。它使得 Ken、dmr、Doug、rhm 以及其他几个人能够互相通信。该功能在其他分时系统中也有提供。但早在 1940 年夏天，George Stibitz 就通过远程电传打字机，从新罕布什尔州的 Dartmouth 连接到新泽西，使用计算器。想要远程工作，自然而然地就想与他人共享信息——无论是数据还是程序。

最早的网络是 ARPANET（始于 1969 年），其目的是资源共享：先进研究计划署（ARPA）认为将其资助的各个项目连接起来，比为每个项目购买昂贵的计算设施更划算。各组织可以登录彼此的计算机并传输文件。文件传输协议（ftp）和远程登录（telnet）很早就被实现了。虽然此前存在机器内部的邮件，但之前没有机器间邮件，因为没有联网的计算机。

到 1970 年代早期，计算机邮件已经相对普及；到 1973 年 9 月，邮件头格式已经足够流行，成为事实上的标准。1970 年代末，ARPANET 规范被重写，纳入了 SMTP（简单邮件传输协议）。

1973 年的消息格式模型是基于 TENEX 操作系统的，该系统在 DEC-10 机器上非常流行。许多后继主机是运行 TOPS-20 或 TWENEX 操作系统的 DEC-20 机器。（TWENEX 是由 BBN 开发，作为他们 TENEX 系统的后续版本。）

那 Unix 用户的情况又如何呢？

在 1976 年之前，从一台机器向另一台机器发送文件几乎是不可能的。那年年底，AT\&T 研究所的 Mike Lesk 写了一个“更好分发的方案”（Mini-System Newsletter，1977 年 1 月），一个月后，这个方案被称为 UUCP。（UNIX-to-UNIX copy，即将 Unix 文件从一台机器或系统复制到另一台的程序。）它设计用于 300 波特率的线路。UUCP 最终在 1978 年 2 月发布。由于其广泛的使用，UUCP 成为 Unix 中最重要的部分之一。Lesk 的发明带来了对改进的需求，因为原始程序无法应对其日益增长的使用负荷。下一版本的 UUCP 由 Lesk 和 Dave Nowitz（以及 Greg Chesson 的贡献）编写，并出现在第七版 Unix（1978 年 10 月）中。但这个版本也无法满足 UUCP 被广泛使用所带来的巨大需求（更多系统、更多软件、更高的需求），1983 年 4 月，Martin Levy 发出呼吁，要求开发一个新的 UUCP 系统。显然，设计之初使用异步 1200 波特调制解调器作为先进技术的 UUCP，已经无法满足不断增长的 Unix 网络需求。

1983 年 4 月中旬，AT\&T 贝尔实验室召集了多位人员召开会议，结果是 Peter Honeyman（登录名 honey）、Dave（dan）Nowitz 和 Brian Redman（ber）共同编写了新版 UUCP。这个版本广为人知，被称为 HoneyDanBer，或者对 System V 用户来说，叫做 BasicNetworkingUtilities 1。

我曾与 Brian Redman 谈过他的工作：

> 我从亚利桑那大学获得硕士学位后，于 1978 年 6 月来到实验室。我在 1977 年获得了微生物学学士学位，我的妻子还需要再读一年。但我原本应该跟随的那个人没给我任何资金支持。于是我转去找生物化学系的另一位教授，负责管理他的计算机。我在亚利桑那大学计算机科学系上过一些课程，当时那个系还比较新。我意识到那年我可以攻读计算机科学硕士学位。无论如何，我正在上课，David Hansen，他算是我的导师，带来了一些实验室的人来进行面试。他告诉全班：“只要你有两只手和两条腿，你就能在实验室赚大钱。”我猜他默认班上每个人都有脑子。
>
> 我参加了面试——最初是为普林斯顿的西部电气面试，那里的工作是在 DEC-10 上，我当时印象很深刻。我还在 Whippany 和 Holmdel 的贝尔实验室面试，最终在 Whippany 得到了工作。所以我妻子一毕业，我们就搬到了新泽西。
>
> 我在 Whippany 的环路传输部门工作……我简直不敢相信有人能付钱让我做这些计算机相关的事情。
>
> 我第一次接触 Unix 是在操作系统课程中读过相关论文。计算机科学系里有 Unix，但我当时用的是 DEC-10，运行的是 TOPS。所以我真正第一次接触 Unix 是来贝尔实验室后。
>
> 我用过 Ratfor 编程语言。《软件工具》这本书对我启发很大，我非常欣赏它强调的概念——简单性、模块化和可重用性。
>
> 后来我来到贝尔实验室，他们告诉我“你会用这个 Unix 系统，这里有个叫 learn 的程序。”它会给你一些信息并问你问题。我记得我输入答案时，程序会说“不对，错了。”但我确信我是对的，就退出程序，开始寻找程序本身。我找到了程序和它的数据库及答案，慢慢开始理解它是怎么工作的。\[learn 由 Lesk 发起，Kernighan 和 Lesk 编写，出现在 V7 版本中，后来被整合进多个 BSD 发行版，但未收录于 System III 或 System V。]
>
> 你知道，如果是书，我会翻到书后面，但这是一台计算机，我就查看了它的文件系统。
>
> 我的老板 Doug Cory 是 Unix 在电话领域最早的用户之一，那个系统叫 COSMOS，用来布线，后来叫 COSMIX。他们有台 11/70 机跑 COSMOS，实际上我有这台机器的前面板——序列号 5001，据说它是美国首台交付的 11/70。我们当时用的是名为 wh5ess 的 11/45，使用 mail，Sam Arnold 引入了 Lesk 的新工具 uucp。我对它很感兴趣，也成了管理员，因为用户越来越多。我发现可以用它从 Murray Hill 获取文件。后来，我们用一台 11/70 替换了 11/45，机器更强大了。
>
> 我们得到的第一台 VAX 叫 mothra。当时我们还在用 300 波特率的调制解调器，后来换了新的调制解调器，可以跑到 1200 波特，然后又有了玻璃终端和一台大机器。于是我问为什么不能跑得更快。他们告诉我 RS-232 最长只能跑 50 英尺，而我们的线长是 150 英尺。我心想，虽然不能达到 9600 波特，但跑得比 1200 波特快还是好的。于是我自己拉了一根线，果然跑到了 9600，甚至 19,200 波特。我的同事看到后说：“嘿，帮我也拉根线。”于是我把这当成了一个项目：我在楼下装了一个配线架，弄成了最先进的技术。当时挺有意思的。那时我已经有几百个用户，我花了整个周末让系统看起来很漂亮。后来开始线路上有噪音和干扰——因为所有线路都是并行运行的。于是我又把它拆开，弄成一团乱麻，结果一切又正常了。
>
> 后来我开始和计算中心合作，他们有一台排版机，我参与了文档工作。我把 man 页送进照排机，努力让系统更易用。\[Redman 的工作几年后直接促成了 USENIX 协会出版这些手册。] 总之，1979 年我去了第一次 USENIX 会议，在圣塔莫尼卡。会上我听说了很多想要获取的东西，也认识了不少人。我想把 Whippany 的东西传到计算中心，于是开始参与 uucp 工作。1980 年 6 月，我在特拉华州遇见了 Peter \[Honeyman]，那是我第一次和他相处。
>
> 我经常去参加会议，认识了很多人，大家交换电话号码，因为我们没法互寄邮件。我记得 Clem Cole，他有我想要的东西，具体是什么我也记不清了。那时候我们有 8 个调制解调器——这在当时很少见，大多数人只有一两个。所以我会打电话给在 Tektronix 的 Clem，说“我们建立个连接吧”，然后就连上了。还有伯克利，他们正在发放第二批发行版，我记得他们说，“我们可以寄给你磁带。”我说，“我等不及了。”于是我们就建立了一个 uucp 连接。

Clem Cole 曾是卡内基梅隆大学的学生，他和 Ted Kowalski 将 Unix V6 从计算机科学系的 PDP-11 移植到了电气工程系的 11/34。（正如 Cole 对我说的，这是“不简单的壮举，因为 CMU 系统为了‘e’机型做了大量修改，而‘原版’的 Version 6 并不支持 34 机型。”）

之后，Cole 在 Mellon 研究所工作，他和 Dan Klein 一起安装了 Unix。当研究所购买了“其中一台最早的 RK07 磁盘（序列号大概是 17）”时，Dan 和我在一周内一起写了它的第一个驱动程序。RK07 给了我们 20 兆字节空间！几乎是无限大了！

Cole 毕业于 CMU，后来在俄勒冈的 Tektronix 找到了工作。

> 我 1979 年 5 月到那里。几个月前，Steve Glaser 发现了一台运行 RSX 的 11/60，劝说 Tektronix 购买了 2 万美元的 V6 许可证，并开始让 Unix 在上面运行。因为 11/60 实际上并不是 11/40（很接近但不完全一样），我在俄勒冈的第一个周末就是和 Steve 一起拆解 11/60，然后装上了一堆来自 CMU 的修改……
>
> 我在俄勒冈的第一个圣诞节，花在安装一台 PDP 11/70 上，那是 Rick LeFaivre、Steve 和我弄到的。这台机器成了第二个重要的 uucp 节点——“teklabs”，运行 V7，我们每天都和“Marxs”机器联系。\[Cole 指的是新泽西贝尔电话实验室的 chico 和 harpo；1981 年 6 月 1 日的 USENET 地图显示了 teklabs 和 chico 的连接。]
>
> 我们写了第一版 VMS 的 TCP，这个版本至今仍然存在，被称为“CMU-Tek”TCP。我们用这台 11/70 来帮忙打造“Magnolia”，一台基于 68000 的多处理器 Unix 工作站，运行 Steve 和我基于 Unix 的操作系统 Magix。我们玩得很开心！
>
> Brian Redman 和我每天通过 uucp 交流重要事情——比如让“adventure”程序能编译（用 C 写的）。实际上，我猜我们是在共享微处理器开发工具和其他不太有趣的东西。当然，我们也分享 11/70 的改动和超频技巧。我们有一个共同的敌人——Digital，那家公司不愿意承认 Unix 是他们应该支持的东西。

Redman 继续讲他的故事：

> 我发现自己一直保持联系，定期发送电子邮件。于是我们就有了一个社区。这就是 NETNEWS 的由来。\[Usenet 是由吉姆·埃利斯和汤姆·特鲁斯科特在 1979 年作为杜克大学的研究生提出的想法。Usenet 的第一个实现由北卡罗来纳大学的研究生史蒂夫·贝洛文编写。于是 USENET 于 1979 年开始，作为北卡罗来纳大学（unc）和杜克大学（duke）之间的信息交流。1980 年加入了第三个主机 phs。阿曼多·斯特特纳和比尔·香农安排了第一条东西向连接（duke 到 ucbvax，同年还连接到 decvax）。现在 USENET 是一个庞大且去中心化的系统联盟，拥有超过 5000 个组和数百万用户。]
>
> 我立即在 chico 上架设了 NETNEWS。我记得花了很多时间琢磨怎么问一个聪明的问题，好得到一个聪明的回答。这一切都是因为不耐烦。即使有好意，当有人说“我给你做个磁带”或者“我会给你寄磁带”时……这根本不够。
>
> 就是在这个时候，NETNEWS 开始了，而 uucp 就崩溃了。Lesk 当初根本没预料到 uucp 现在的用途，也没预料到这样的负载。我的问题是 NETNEWS 会产生大量文件。当 NETNEWS 文件传输完毕时，Unix 会执行 uuxqt 命令，但当流量很大时，连接会在某个时刻断开。还没恢复，另一个 uucp 连接又来了，带来几百个新文件。查看目录时会超时，因为文件太多了。
>
> 所以我对 uucp 的第一个重大贡献是为我通信的每个站点设置不同的目录。
>
> 我做完这些后，Honeyman 发邮件说：“大家聚一聚，聊聊这 UUCP 的事情，把所有修改合并起来，大家都用同一个版本。”于是我们发出通知，在 Murray Hill 召开了会议。\[当时马克·霍顿也在场——他那时已经在 Columbus，Honeyman、我、Bellovin，还有所有实验室运行系统的人都来了。Honeyman 应该有出席名单。] 基本上，Honeyman、我和 Dave Nowitz 负责合并修改内容。史蒂夫·贝洛文也做出了重要贡献。
>
> 我们那天晚上开始改代码，工作划分得很好：我负责目录管理，Honeyman 负责拨号相关，Nowitz 关注安全问题。我们分工合作，最终完成了任务。

Bellovin 修订了他的 NETNEWS 代码，随后由 Steve Daniel 和 Truscott 进一步修订，形成了 A News。1981 年，Mark Horton（加州大学伯克利分校研究生）和 Matt Glickman（高中生）将 A News 改写成了 B News。1987 年，多伦多大学的 Henry Spencer 和 Geoff Collyer 推出了替代版本 C News。还有许多其他对 NETNEWS 的有益修改，来自 Spencer Thomas、Rick Adams、Ray Essick、Rob Kolstad 等人。

但让我回到 UUCP。

感谢 Peter Honeyman，这里是 1983 年会议记录的一部分（用 Peter 独特的正字法）：

> uucp 爱好者兴趣小组的第一次（也是最后一次）会议于 1983 年 4 月 20 日举行。受邀者包括 allegra! honey、vax135! martin、eagle! karn、rabbit! ark、mhb5b! smb、harpo! ber、cbosgd! mark、floyd! trb、research! rtm 和 eagle! dan。其他到场的还有来 > 自 USG、mhtsa! lsc、mhtsa! brad、whuxlb! pep 和 gummo! mmp 的代表。以下是不删减的会议记录。
>
> 发件人：honey 1983 年 4 月 20 日 星期三 00:46:26
>
> 收件人：uucplovers
>
> 主题：会议记录
>
> 抄送：dmr doug
>
> 请原谅我在下面会议记录中的编辑旁白，此会议由 levy 召集，讨论 uucp 相关问题。今日聚会的成员有
>
> eagle! dan、vax135! martin、ihnp4! gjm、gummo! ber、mhtsa! lsc、mhb5b! smb、mhtsa! brad、eagle! karn、whuxlb! pep 和 allegra! honey
>
> 第一个讨论主题是企业电子邮件项目及其配套的网络行动中心。行动中心似乎由 452（员工）和 774（设备与组织支持）共同管理。murakami 给人的印象是这是实验室内永久存在的设施，任何启动问题都是暂时的。L.sys 数据库随着新数据的收集和标准的推广逐渐成型。关于如何处理每月的 L.sys，讨论达成共识：各站点应继续维护本地 L.sys，并且优先搜索本地文件，类似于 koenig、honeyman 以及其他人的做法。
>
> 会议的大部分时间都被关于 uucp 破解的热烈讨论占据。uucp 有许多版本，站点多样，主要竞争版本是 usg 6.0、morris \[Robert T. Morris] 的新代码，以及 tom truscott 的破解版本。cohen 严肃提醒，想把好东西合并进 6.0 很难，不过大家仍举起公司的旗帜致敬，并同意以组织版作为起点，制作一个能满足所有人（尤其是我们自己）的版本。
>
> 主要的改进建议是对轮询目录使用哈希方案。truscott 使用 C 和 D 文件（还有其他文件，想必如此）的独立目录，redman 和其他人则用远程站点名称作为子目录。经过热烈讨论，大家达成共识后者更为健壮。levy 提议根据机器名称的短前缀作为哈希函数，这引起了大家的兴趣。虽然 usg 的 setuid 进程中 mkdir 存在问题，bellovin 耐心解释了绕过该功能的技巧；经过三四次反复，会议回归正轨。大家认为 cico 或某个守护进程应偶尔在轮询目录中执行 rmdir。最终对哈希方案的所有细节未达成完全一致，估计会以适合信息时代的方式继续讨论。
>
> 最后，我们同意拿最新的 6.0 版本 uucp，将其改得面目全非（即修复漏洞并使其运行良好）。honeyman 负责 conn.c，redman 负责轮询目录相关的破解，levy 自愿编写 L.sys 编辑器并帮助 murakami 统一 action L.sys，bellovin 负责将轮询目录的修改合并到 uuxqt。cohen 指出 usg 不太可能认可任何属于 ucb 系列的东西，而 nowitz 反对依赖 ifdefs。大家觉得可以把特殊处理隐藏在单个文件中，以表现为对版本 7 的兼容支持，这是一种透明但无害的谎言。无论如何，这问题属于外围。
>
> 议程上的最后话题是公司推动的安全意识提升，结果变成了一场争吵，过程中多方名誉受损，某些偏执反应未被认真对待，未能达成共识。honeyman 支持 mcilroy 反对允许远程机器拉取文件的立场，进一步主张只允许本地集群内访问，甚至建议允许从非 uucppublic 目录拉取文件，以避免一个远程站点拉取另一个远程站点发送的文件。redman 指出 L.sys 中唯一值得保护的信息是电话号码（无疑是最不安全的数据）。redman 征求大家对即将出台的 GEI 规定的看法。
>
> 在众人因饥饿发出明显抱怨后，决定按照 uucp 破解者们的传统，前往当地一家中餐馆聚餐。但后来该决定被撤销，改为去 oak room（这是个不详的预兆）。

Oak Room 是位于 Murray Hill 的贝尔实验室食堂；几年前之前，这里还有正式的桌边服务。

在这场关于 uucp 的长时间讨论之前，我提到了 ARPANET 和 TCP，以及 ping。由于 Mike Muuss 参与了最早版本的 TCP 并且是 ping 的作者，我认为他的故事非常值得一听。

我在霍普金斯大学读本科。我们有一个相当独特的情况：当我到达时，PDP11/45 正在运行 RSTS（DEC 的资源共享分时系统），Unix 只运行几个小时一天。系里说除非能同时运行 RSTS，否则不能运行 Unix……\
于是我们做到了，这成为了我们的第一个软件产品——在 Unix 下运行 RSTS。那是真正开始运作的时候，是七五年年底。秋天我们升级到了 Version 6。这也带来了影响。我把一份拷贝寄给了负责 Cray2 Unix 项目的那个人……

Muuss 于 1979 年毕业于霍普金斯大学，并开始在弹道研究实验室工作。那年九月，他参与实现了原型 BRLNET 高速局域网，该网络是他当年早些时候根据美国陆军合同设计的。1980 年初，Muuss 扩展了 BRLNET 协议，并领导一个团队将伊利诺伊大学的 NCP 功能移植到 PDP-11 Unix 上。团队安装了一台 11/34。1981 年末，Muuss 发现了实验性的 TCP/IP 套件，并开始在 PDP-11 上为 BRL/JHU Unix 实现它，而不是继续扩展 BRLNET。更重要的是，Muuss 开始了一份名为 The TCP/IP Digest 的电子刊物，通过 ARPANET 和 USENET 向超过 700 名订阅者发行。最重要的是，Muuss 的许多工作被纳入了两个军用标准：1777 和 1778。几乎所有现有的 TCP/IP 实现都包含了 Muuss 在 BRL 开发的协议软件。Muuss 告诉我：

> 我们甚至还干过一段时间的网关业务。Ron Natalie 是我那里的主要开发人员。我们构建了一个小型操作系统，把各种设备从 PDP-11 网关接入 ARPANET。所以我们做过一段时间的网关业务。然后，在一九八三年，我们迈出了下一大步，争取到了一个大型光纤拨款。AT\&T 刚刚推出了带状光纤……我们购买了带有 145 根光纤的主干电缆。我们立刻建立了一个局域网，后来又推进了真正的光纤网络。

那是十年前的事了。根据新闻报道，一九八四年弹道研究实验室网络无可匹敌。TCP/IP 协议被同时送到了 BBN 和 Berkeley。我将在第十八章回到协议的开发内容。


---

# 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/14-utilities.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.
