文档?什么文档?
最后更新于
最后更新于
“使用 UNIX 来教授操作系统课程的一个优势是,它的源代码和文档可以轻松地装进学生的公文包里。”
—— John Lions,新南威尔士大学,
指第 6 版,大约 1976 年
多年来,要获得深入了解 Unix 的知识,有三个简单的途径:
阅读源代码。
自己写一个版本。
打电话给程序的作者(或者通过网络发电子邮件询问)。
Unix 就像荷马史诗,是靠口耳相传流传下来的智慧。当时根本没有不懂内核黑魔法的严肃 Unix 用户——或者至少他们身边都有精通内核的人。那时候真正写下来的文档,就是臭名昭著的 Unix“man 页面”——其实不过是一份写给已经知道自己在做什么的人看的备忘录合集。Unix 的文档精炼到什么程度呢?你一个下午就能把它们全读完。
Unix 的文档系统最初是一款叫做 man
的单一程序。
man
是款很小的工具程序,它接受用户提供的参数,找到对应的文件,将文件通过带有“man”宏(这是一组全世界只有在这里才用得上的文本格式化宏)的 nroff
处理,然后把输出传给 pg
或 more
来显示。
最初,这些零碎的文档被称为“man 页面”,是因为每个程序的条目差不多就只有一页(常常还不到一页)。
在 man
诞生的年代来说非常不错。但那个年代早已一去不复返了。
这些年来,man
页面系统缓慢地发展和成熟。值得称道的是,它没有像操作系统的其他部分那样,变成一团乱麻的代码和令人困惑的程序。但另一方面,它也并没有变得更有用。事实上,在近 15 年里,Unix 的在线文档系统只进行过两次重大改进:
catman,程序员“突破性”地意识到,可以把 man
页面同时存储为 nroff
源文件和已经预处理过的文件,这样在显示时能更快。
在今天这个处理器飞快的时代,catman
这种小把戏已经没有必要了。但那些 nroff
处理后的文件仍然占用了几兆磁盘空间。
makewhatis、apropos 和 key(后来并入了 man -k
),这是一款构建 man
页面排列索引的系统,能让用户在不知道程序确切名称的情况下查找 man
页面(实际上这些工具在今天的很多 Unix 版本中默认是禁用的,导致不知情的用户运行时只会得到一条莫名其妙的错误信息)。
与此同时,电子出版的进展早已把 Unix 的 man 系统远远甩在了后头。今天的超文本系统只要点击鼠标,就可以在大型数据库中从一篇文章跳转到另一篇;而 man 页面则只是简单地在每页底部列出一个叫做“SEE ALSO”的段落,然后要用户自己在提示符后输入“man 某某”来继续查看。
在线文档的索引又如何?今天你可以买到一张光盘版的《牛津英语词典》,它能索引整个多卷本中出现的每一个单词;而 man 页面却仍然只能靠程序名称和一句话的描述来索引。就连现在的 DOS 都已经有带索引的超文本文档系统了。man 页面呢?仍然按照 DEC 打印终端的 80 列、66 行格式来排版。
公平地说,一些厂商已经在尴尬之下开始编写自己的超文本文档系统。在这些系统中,man 成了一个演化上的死胡同,往往出现的情况是:man 页面不是已经过时,就是干脆根本缺失。
对今天试图使用 man 的人来说,一个最大的问题是:让这个程序知道你的 man 页面到底存放在系统的哪个位置。早年间,找文档是件轻松的事:它们都在 /usr/man
里。
后来,man 页面被按章节分到了不同目录里:/usr/man/man1
、/usr/man/man2
、/usr/man/man3
,诸如此类。很多站点还加上了 /usr/man/manl
,用来放“本地”man 页面。
情况开始变得混乱,是从 AT&T 草草推出 System V 开始的。/usr/man/man1
被改成了 /usr/man/c_man
,仿佛以一个字母的方式比一个数字更容易记住。在某些系统里,/usr/man/manl
被挪到了 /usr/local/man
。而那些售卖自家 Unix 应用的公司也开始塞进他们自己的“man”目录。
最后,伯克利修改了 man,使它可以去一组由环境变量 MANPATH
指定的目录里寻找 man 页面。这个点子本来很好,只是有个小小的问题:它根本没用。
日期:1992 年 12 月 9 日 星期三 13:17:01 -0500
收件人:Unix 痛恨者
主题:man page,man page,谁有 man page?
对那些愿意承认自己对 Unix 略知一二的人来说,你们知道在
/usr/man
里有一些联机手册页,这通常是查找某个函数文档的好地方。所以当我昨天试图在一台 SGI Indigo 上查找 lockf(3) 的手册页,想知道lockf
究竟有多不具可移植性时,我输入了:什么都没出来,于是我开始在
/usr/man
里查找。尽管我知道东西可能不在那,而且我的MANPATH
已经包含了/usr/man
(以及我在其他系统上找到有用手册页的所有目录)。我本以为会看到如下内容:
但我实际看到的是:
(
%*&@#+!
SysV 式做法)SysV 和 BSD 除了在
ls
格式上的区别之外,我觉得这还是挺奇怪的。但我继续寻找任何看起来像是cat3
或man3
的东西:现在,在 man3 里只找到一个 X 子目录显然是有问题的。接下来怎么办?用暴力方法:
等等,系统上居然没有
lockf.3
的手册页?那就换种办法:给这台机器的一位普通用户发邮件。他回复说他也不知道手册页在哪儿,但当他输入
man lockf
时是能看到的。他的MANPATH
比我的还少几个目录,基本没什么帮助。所以我试试非暴力的方法:
啊哈!
/usr/catman
!这是一个不在我MANPATH
里的目录!那就去看看lockf
是否在那儿。System V 的默认格式真烂。这到底搞什么鬼?
成了!文件溢出了屏幕,因为
/bin/ls
的 SysV 式乱象。最好只列出一部分文件:我运气不错,在 xterm 的顶部看到一个叫做“standard”的目录,但文件又溢出了屏幕……
太好了。它被 compress(1) 压缩过了。为啥要压缩,而不是以纯文本保存?SGI 是不是觉得压缩手册页能节省的空间能抵得上那些巨大的 RISC 可执行文件?总之,既然找到,不如读一下。
唉。我忘了
zcat
有多么不灵活。这根本就不是 compress(1) 压缩的?咆哮。他们至少也该让人能读到它。于是我编辑了我的
.cshrc
,把/usr/catman
加到已经冗长的MANPATH
中,然后再试一次:果然,它在那里,而且和 Unix 的其他部分一样,不具可移植性。
Unix 对联机文档的处理方式在你只需记录几百个程序和命令,且大部分内容你能记住的情况下效果不错。但当系统中的条目数量接近一千时,这种方式开始崩溃;如果再增加更多条目,由分布在整个大陆数百名作者编写,大脑便会因膨胀和瘙痒而发生痉挛和怪异抽搐。
日期:Thu, 20 Dec 90 3:20:13 EST
收件人:Unix 痛恨者
主题:如果打算写文档,就别把程序叫做“local”
事实证明,根本无法为名为“local”的程序获取手册页。即使你明确指定手册章节号(真是个很棒的组织方案,不是吗?),你也会收到以下消息:
Unix 的 shell 一直是 Unix 文档编写者的难题:毕竟,shell 有内置命令。内置命令应该单独写成自己的 man 页面,还是写在 shell 的 man 页面里?传统上,这些程序都是写在 shell 的 man 页面里。这种做法在逻辑上是连贯的,因为并没有独立的 while
、if
或 set
命令。那些看起来像真实命令的命令其实是错觉。不幸的是,这种态度给新用户带来了麻烦——而文档的初衷正是为他们服务。
举个例子,用户可能听说 Unix 有一个“history”功能,可以免去重复输入之前命令的麻烦。想了解更多关于“history”命令的细节,刚入门的新手可能会尝试:
这是因为“history”是 shell 的内置命令。内置命令有很多。试着找一个完整的列表(没关系,查看 sh 或 csh 的 man 页面并不算作弊)。
当然,也许让每个 shell 的内置命令写在 shell 本身的 man 页面上,而不是单独出一页,反而更好。毕竟,不同的 shell 里有同名但功能不同的命令。试想如果要给 set
命令写一篇“man 页面”,那篇 man 页面大概只有一句话:“你想要哪个 set
命令?”
日期:1992 年 9 月 24 日 星期四 16:25:49 -0400
收件人:Unix 痛恨者
主题:一致性对于 Unix 弱鸡来说太累赘
我最近不得不帮助一位沮丧的 Unix 新手解决这些难题:在 Bourne shell(“标准”的 Unix shell)下,
set
命令用于设置选项开关。在 c shell(另一种“标准”Unix shell)下,set
用于设置 shell 变量。如果你执行man set
,你会得到其中一种命令的定义(取决于该特定 Unix 系统供应商的随意决定),但通常不会同时得到两者,有时甚至都没有,且绝对不会提示存在另一个冲突的定义。错误地在一个 shell 中使用另一个 shell 的
set
语法会静默失败,完全没有任何错误或警告。更糟的是,在 Bourne shell 下输入set
会列出 shell 变量!Craig
未记录的 shell 内置命令不仅对新手来说是个谜。
当人工智能领域的权威 David Chapman 向 Unix 痛恨者抱怨说他很难使用 Unix 的 fg
命令,因为他记不住 C-shell 使用的“作业编号”时,Robert Seastrom 给 David 发了一条有用的信息,并抄送了邮件列表:
日期:1990 年 5 月 7 日 星期一 18:44:06 EST
收件人:zvona@gang-of-four.stanford.edu
抄送:Unix 痛恨者
为什么你不直接输入
fg %emacs
或者干脆%emacs
?得了,David,Unix 里已经有这么多失败了,你没必要去发明想象中的失败来抱怨!<笑>
可悲的是,David 并不知道他只需输入 %emacs
就能重新启动挂起的 Emacs 任务。他从未在任何地方见过相关文档。
David Chapman 并非个例,许多在 Unix 痛恨者邮件列表上的人也发邮件表示,他们同样不知道 C-shell 那些奇怪的作业控制功能。(阅读本书早期稿件的大多数人也不知道!)Chris Garrigues 比大多数人更愤怒:
日期:90 年 5 月 8 日 星期二 11:43 CDT
抄送:Unix 痛恨者
主题:回复:今天的抱怨:
fg %3
这有文档说明吗,还是我得买个源码许可学着读 C 语言?
man fg
显示的是CSH_BUILTINS
的手册页,但我从没能在里面找到什么有用的信息。如果我在这页手册中搜索“job”,根本找不到相关内容。不过,它确实告诉我,如果输入% job &
,我可以把一个作业从后台拿出来,再放回后台。我知道这个功能我会用得远比通过名字引用作业要频繁得多。
一些较大的 Unix 工具也提供自己的在线文档。对于许多程序来说,“在线”文档通常表现为一条晦涩难懂的单行“使用说明”。以下是 awk 的“使用说明”行:
有用吗?更复杂的程序会有更详细的在线文档。不幸的是,你不能总指望文档和你运行的程序完全匹配。
日期:1989 年 1 月 3 日 16:26:25 EST(星期二)
收件人:Unix 痛恨者
主题:一个阴谋被揭露
经过数小时的专注研究,我得出了一个重要结论。
Unix 烂透了。
这对你们中的一些人来说可能是个惊讶,但这是真的。
这项研究已被全球独立研究人员验证。
更重要的是,我们说的不是那种二流的烂。
这是顶级水平。烂得一塌糊涂。严重的胡佛主义。
比如说,看看下面这个例子:
有哪个生产环境,尤其是足够老可以开车、投票和喝 3.2 瓶啤酒的生产环境,会拒绝它告诉你输入的命令?
为什么用户指南与现实毫无关联?为什么命令名称晦涩难懂,与功能毫无关系?
我们不知道 Heiny 的问题是什么;就像本章提到的其他几个例子一样,他的错误似乎已经修复了。或者也许它只是转移到了另一个应用程序。
日期:1992 年 9 月 29 日 星期二 19:47
收件人:Unix 痛恨者
主题:无需评论
实际上,最好的 Unix 文档形式往往是对程序的目标代码运行 strings
命令。通过 strings
,你可以获得程序硬编码的文件名、环境变量、未记录的选项、晦涩的错误信息等的完整列表。例如,如果你想知道 cpp 程序在哪里搜索 #include
文件,使用 strings
比查 man
页面要有效得多:
嗯……请稍等一下:
真是糊涂啊。NEXTSTEP 的 /lib/cpp
会调用 /lib/cpp-precomp
。你在 man 页面上也找不到这条记录:
别责怪 Ken 和 Dennis 导致了今天 Unix 文档的破烂境况。当文档框架被建立时,计算机行业其他领域流行的文档标准并不适用。陷阱、漏洞和潜在问题被记录得比功能还频繁,因为阅读这些文档的人大多是系统开发者。对于许多开发者来说,Unix“man”页面真正的作用就是收集错误报告的地方。认为 Unix 文档是为新手、或仅仅是不熟练的用户、程序员和系统管理员准备的,这是最近才有的观念。遗憾的是,由于 1970 年代中期确立的 Unix 文档模型,这种观念并没有取得多大成功。
Unix 世界承认这种糟糕状况,但并不为此道歉。《Life with Unix》相当平淡地陈述了 Unix 对文档的态度:
最佳的文档是 UNIX 源代码。毕竟,系统在决定下一步该做什么时,正是使用这些源代码作为文档!手册是对源代码的意译,通常是在不同时间由不同于写代码的人编写的。把它们当作指导原则。有时它们更像是愿望……
然而,转向源代码时,常常会发现手册中未记录的选项和行为。有时你会发现手册中描述的选项在源代码中未实现且被忽略。
而且这还只是针对用户程序。内核内部的情况更糟。直到最近,几乎没有厂商提供用于编写新的设备驱动程序或其他内核级功能的文档。人们开玩笑说,“所有需要内核函数文档的人,大概都不该使用它们。”
事实却更为险恶。内核之所以没有文档,是因为 AT&T 将这段神圣的代码作为“商业机密”保护起来。任何试图写出介绍 Unix 内部结构的书籍的人,都有可能面临诉讼。
事与愿违,AT&T 的计划反而适得其反。在缺乏书面文档的情况下,想要了解内核或用户命令的具体工作原理,唯一的方法就是查看源代码。因此,Unix 源代码在操作系统的头 20 年里被广泛盗版。顾问、程序员和系统管理员并不是因为想编译它然后制造非法的 Unix 克隆版才复制源代码的,而是因为他们需要源代码作为文档。Unix 源代码的副本从大学流向附近的高科技公司。这当然是违法的,但属于有理由的犯罪:Unix 厂商提供的文档根本不够用。
这并不是说源代码中包含什么有价值的秘密。任何既能接触源代码又有兴趣阅读它的人,很快都会遭遇一个令人不快的惊喜:
尽管这条注释最初出现在 Unix 第 6 版内核源代码中,但它同样适用于任何原始的 AT&T 代码,那些代码充满了行内手工优化和微妙的黑客手法。寄存器变量名如 p、pp 和 ppp 在同一个函数的不同部分被用来执行多种不同的任务。注释中写着“这是个递归函数”,仿佛递归是个难以理解的概念。事实上,AT&T 对用户和程序员文档的机构态度,反映了他们对写作整体上的马虎态度,尤其是对编写计算机程序的态度。
很容易被识别一位马虎工匠的作品:你会看到裂缝上涂了油漆,一块补丁又盖着另一块补丁,一切都靠口香糖和胶带黏在一起。面对现实吧:重新设计和从头构建某样东西,需要思考和真正的努力。
日期:Thu, 17 May 90 14:43:28 -0700
收件人:Unix 痛恨者
我喜欢这个。摘自 man man:
诊断信息
如果你使用
-M
选项,并指定了一个不存在的目录,错误信息会有些误导。假设目录/usr/foo
不存在。如果你输入:你会收到错误信息“没有 ls 的手册条目”。你应该收到一个指示目录
/usr/foo
不存在的错误信息。写这段文字可能花的时间比修复这个错误还多。
日期:1992 年 4 月 24 日 星期五 12:58:28 PST
机构:SGI TechPubs
新闻组:talk.
主题:无言的 Unix
【在一次关于文档无用性的特别激烈的网络争论中,我写下了以下提案。我从未发布过,因为我很怂……现在终于把它发出来,供大家参考。】
无言的 Unix
好吧!我已经完全被这里提出的关于文档无用性的论点说服了。事实上,我已经相信文档是一种毒品,而我对它的依赖是人为的。我可以借助专业帮助克服我的成瘾。更重要的是,我觉得有道德义务停止靠兜售这种无用的“毒品”谋生。我决定回去读数学研究生,重新教育自己,摆脱这个寄生行业。也许这只是暴露了我对文档成瘾的深度,但我确实认为 SGI 需要在下一次发布中附带一份文档。我认为这本书只是过渡性的。下一次发布时,我们可以取消它。
我的提案如下:
标题:“无言的 Unix”
目标读者:Unix 新手。
概述:给出一种在没有文档的情况下接近 Unix 的通用策略。提出适用于破解任何操作系统、无需文档辅助的通用原则。
目录:
引言:‘无文档’哲学概述
为什么手册是邪恶的
为什么 man 手册是邪恶的
尽管如此,为什么你仍然应该读这本书
“这是你 EVER 会读的最后一本手册!”
第 1 章:猜测哪些命令可能存在
第 2 章:猜测命令可能叫什么名字
Unix 式不可预测的缩写
使用场景:“grep”
第 3 章:猜测命令可能接受哪些选项
破解隐晦的用法提示
使用场景:“tar”
猜测顺序何时重要
使用场景:SYSV“find”
第 4 章:判断命令何时成功:成功时的沉默
错误恢复
第 5 章:口传传统:你的朋友
第 6 章:获取并维护个人 UNIX 导师
喂养你的导师
保持导师愉快
完整新闻订阅的重要性
为什么你的导师需要最快的机器
免费可乐:导师生命的灵药
维护导师健康
他们什么时候睡觉?
第 7 章:故障排除:当你的导师不愿与你交谈时
识别愚蠢的问题
安全地提问愚蠢的问题
第 8 章:接受你的压力
应对失败
(或者,也许只有第 6 和第 7 章是真正必要的。是的,就这么定了:我们叫它 Unix 导师维护手册。)
发件人:Rainbow Without Eyes
发件人:Rob Austein
发件人:Systems Anarchist
发件人:Robert E. Seastrom
发件人:Chris Garrigues
收件人:Robert E. Seastrom
发件人:Reverend Heiny
发件人:Mark Lottor
发件人:David Chapman
发件人:(C J Silverio)