欢迎,新用户!就像装满六发子弹的俄罗斯轮盘赌
最后更新于
最后更新于
有一辆 Ken Thompson 参与设计的汽车。与大多数汽车不同,这辆车没有速度表、油量表,也没有那些困扰现代司机的各种愚蠢警示灯。而如果司机犯错,仪表盘中央会亮起一个巨大的“?”问号。Thompson 说:“有经验的司机通常会知道出了什么问题。”
——佚名
计算机系统的新用户(甚至是经验丰富的用户)都需要系统给予一定程度的友好支持。至少,友好的计算机系统应为其用户提供以下便利:
符合功能逻辑的命令名称
对危险命令的谨慎处理
命令行为及其选项和参数解释上的一致性和可预测性
容易查找且易读的在线文档
命令失败时提供可理解且有用的反馈
Unix 在开发期间,并未接待任何访客。每位来访者都是戴着安全帽的承包商,被指派去完成营房中尚未完成的部分。不幸的是,不仅从未邀请过工程师参与设计,甚至从未预见和规划过他们的需求。因此,许多标准设施,比如抽水马桶、中央供暖和可开启的窗户,现在都极其难以且昂贵地进行改装。尽管如此,建造者们仍对它的设计赞叹不已,以至于他们甘愿躺在没有烟雾探测器的房间地板上睡觉。
在大部分历史中,Unix 是大学和工业研究人员的研究平台。随着廉价工作站的爆炸性增长,Unix 进入了新时代——交付平台时代。这个变化很容易确定时间点:当工作站厂商为了降低非开发者的价格,将 C 编译器从标准软件套件中拆分出来时。这一变化的界限在化石记录中略显模糊,但大多发生在 1990 年左右。因此,只有在过去几年中,厂商才真正开始关心终端用户的需求和期望,而非程序员。这也解释了为什么如今公司们试图编写图形用户界面来“替代”shell 的需求。我们并不羡慕这些公司的任务。
Unix 新用户总是对 Unix 所选择的命令名称感到惊讶。无论在 DOS 还是 Mac 上接受多少培训,都无法为你准备好去欣赏那些神秘而简短的两个字母命令,比如 cp
、rm
和 ls
的“壮丽之美”。
我们这些使用过七十年代初期输入/输出设备的人怀疑,这种简短命令的退化,源于当时常用的 ASR-33 电传打字机的速度、可靠性,尤其是键盘的限制。与现代键盘不同,现代键盘按键行程的设计基于反馈原理,所需力量仅是关闭微动开关的力,而当时电传打字机的按键(据记忆)需要行程超过半英寸,而且需要施加类似骑自行车发电机的力量。用这些“怪兽”触摸打字,甚至可能撞破你的指关节。
如果 Dennis 和 Ken 用的是 Selectric 打字机而不是电传打字机,我们现在可能会打“copy”和“remove”而不是“cp”和“rm”。这再次证明,技术既限制了我们的选择,亦扩展了我们的可能。
经历了二十多年,继续沿用这种传统的理由是什么?历史的不可抗拒力量,也就是现有的代码和书籍。如果某个厂商把 rm
替换成“remove”,那么所有介绍 Unix 的书籍将不再适用,该厂商系统上的所有调用 rm
的 shell 脚本也将失效。这样的厂商还不如干脆停止执行 POSIX 标准。
一个世纪以前,快速的打字员被键盘卡住,于是工程师设计了 QWERTY 键盘来减慢他们的速度。计算机键盘不会卡键,但我们至今仍在使用 QWERTY 键盘。再过一百年,世界仍然会继续使用 rm
命令。
用户非常关心他们的文件和数据。他们使用计算机来生成、分析和存储重要信息,信任计算机能够保护这些宝贵的资料。没有这种信任,用户与系统的关系就会变得紧张。Unix 滥用我们的信任,固执地拒绝保护用户免受危险命令的伤害。特别是 rm
这个最危险的命令,其存在的唯一理由就是删除文件。
所有 Unix 新手都曾“意外”且不可恢复地删除过重要文件。即使是专家和系统管理员也会“意外”删除文件。因丢失时间、努力和文件恢复而产生的费用可能每年达数百万美元。这本应是个值得解决的问题;我们不明白为什么 Unix 用户对此视而不见。难道真的喜欢祸不单行吗?
文件在 Unix 下比在任何其他操作系统中更频繁地“死亡”并需要“重生”,原因如下:
Unix 文件系统没有版本号。自动文件版本控制,会给文件的新版本赋予新名字或编号后缀,从而保留文件的旧版本,避免新版本覆盖旧版本。而在 Unix 中覆盖经常发生。
Unix 程序员对错误报告和检查的态度极其宽松。许多程序根本不检查输出文件的所有字节是否能成功写入磁盘,有些甚至不确认输出文件是否创建成功。但是这些程序在完成后肯定会删除输入文件。
是 Unix shell(命令行解释器),而不是客户端程序,来扩展通配符“”。shell 扩展“”导致客户端程序(如 rm
)无法进行合理检查以防止灾难。即使是 DOS 也会验证像 del *.*
这样危险的命令,但在 Unix 中,删除文件的程序无法区分用户是输入了:
还是
如果能保存并传递原始命令行给被调用的客户端命令,这种情况会有所改善。也许可以利用环境变量来实现。
文件删除是永久性的。Unix 没有“undelete”(撤销删除)命令。其他更安全的操作系统中,删除文件会将文件所占用的磁盘块标记为“可用”,并将目录项移动到一个专门的“已删除文件”目录里。仅当磁盘空间不足时,才会回收这些已删除文件占用的空间。
大多数操作系统采用这种“删除 - 清空”的两步机制来将文件占用的磁盘块归还给系统。这并不是高深的技术,甚至早在 1984 年,Macintosh 就将“扔进垃圾桶”和“清空垃圾桶”区分开了。Tenex 在 1974 年就已经实现了这一点。
DOS 和 Windows 给你的东西更像是带有存水弯的污水管道,而不是垃圾桶。它们只是简单地删除文件,但如果你想“伸手”把文件找回来,至少还有一些能购买的工具来完成这项工作。这些工具确实有效——不过只是有时有效。
这四个问题相互纠缠,导致了无谓但可预见且每天都会发生的文件删除。比 Unix 出现之前,人们已经理解并广泛使用了更好的技术。而如今,随着 Unix 被接受为世界上的“标准”操作系统,这些技术正逐渐被遗忘。
欢迎来到未来。
上述原则结合起来,形成了现实生活中的恐怖故事。Usenet 新闻组 alt.folklore.computers 上的一系列交流说明了我们的观点:
日期:1990 年 1 月 10 日 星期三
主题:
rm *
新闻组:alt.folklore.
有没有人曾打算输入:
却不小心输入成了:
现在你得到一个新的空文件叫做“o”,但它占用了大量空间!
实际上,你甚至可能不会得到名为“o”的文件,因为 shell 文档并没有明确说明输出文件“o”是在通配符展开之前还是之后创建的。shell 虽然是编程语言,但它不是很精确。
日期:1990 年 1 月 10 日 星期三 15:51 CST
主题:回复:
rm *
新闻组:alt.folklore.computers
我也经历过类似的
rm
灾难。有一次,我要从磁盘上删除一个文件系统,类似于/usr/foo/bin
。我当时在/usr/foo
目录下,已经通过以下命令删除了系统的几个部分:……诸如此类。但当轮到删除
./bin
时,我漏打了那个点。系统对此反应很糟糕。
Unix 并没有设计成能在失去其 /bin
目录这种致命打击后继续存活的智能操作系统。一个智能的操作系统本该给用户一个恢复的机会(或者至少确认用户是否真的想让操作系统变得无法使用)。
Unix 爱好者把偶尔的文件删除当作正常现象。例如,看看 comp.unix.questions 中的以下摘录:
6)如何“恢复删除”的文件?
总有一天,你会不小心输入类似这样的命令:
结果你实际上删除了
*
而不是*.foo
。把这看作是一个成长的仪式。当然,所有体面的系统管理员都应该定期做备份。联系你的系统管理员,看看是否有最近的备份文件可用。
“成长的仪式”?在其他任何行业,制造商都不可能对有缺陷的产品持如此轻率的态度。“但法官大人,爆炸的油箱不过是成长的仪式。”“各位陪审团成员,我们将证明因安全装置失效导致的损害……”
“电锯对它的用户来说也只是一条成长的必经之路。”“法庭阁下,我们将证明,被基廷先生骗走毕生积蓄的退休人员,也只是经历了一条成长的必经之路。”没错。
rm
的行为来解决问题被 rm
咬了几次之后,人们往往会冲动地给 rm
命令设置别名,使其变成 rm -i
,或者更好的是,用别的程序替换 rm
命令,将要删除的文件移动到一个特殊的隐藏目录,比如 ~/.deleted
。这些做法会让无辜的用户产生一种虚假的安全感。
日期:1990 年 4 月 16 日星期一 18:46:33
收件人:Unix 痛恨者
主题:删除
在我们的系统上,
rm
并不删除文件,而是以某种晦涩的方式重命名文件,以便所谓的“undelete”(不是unrm
)可以恢复它。这让我在删除文件时有些不小心,因为我总以为自己可以随时恢复它们。其实不然。Emacs 中的删除文件命令并不是这样工作的,Dired 中的 D 命令也不是如此。原因当然是因为撤销删除的协议并不是操作系统文件模型的一部分,而只是某个叫做“rm”的 shell 命令中被人为拼凑进去的一部分。
因此,我必须在脑海中保持两个不同的概念——“删除”文件和“用
rm
删除”文件,并时刻提醒自己,当我的大脑对我的手说“删除它”时,我实际上是在执行哪个操作。
一些 Unix 专家顺着 Phil 的论点推向逻辑上的荒谬,坚持认为最好不要让像 rm
这样的命令变得哪怕稍微友好一点。他们的论点虽然不是用我们所用的表达方式,但认为试图让 Unix 更加友好,赋予它基本的便利设施,实际上会让它变得更糟。不幸的是,他们是对的。
日期:Thu, 11 Jan 90 17:17 CST
主题:不要重载命令!(原主题:Re:
rm *
)新闻组:alt.folklore.computers
我们打断本新闻组的正常内容,带来以下信息……
请,拜托,请不要鼓励大家用“安全”命令去重载标准命令。
(1)人们通常把它放在
.cshrc
文件错误的位置,导致那些想用“rm”命令删除文件的脚本莫名其妙地要确认,或者误以为文件已被删除,结果把磁盘填满了。(2)没有办法保护所有可能意外删除文件的情况,如果你保护了一个常用的,用户就会认为“任何操作都可以撤销”(绝对不是真的!)。
(3)如果用户请系统管理员(我现在正干这个活)在终端帮忙,命令不按正常方式运行,当你有用户要帮忙,还有四个“紧急:现在需要处理”的任务排队时,这真的令人抓狂。
如果你想要
rm
命令要求确认,请用:并且不要用
rm
!哎,人们,这有多难?!?现在恢复你们原定的“我敲代码敲得那么久,机器只有 0,没有 0 和 1”的讨论……
只是另一个系统黑客
最近,有人在 comp.unix.questions 发布请求,征集系统管理员们最喜欢的管理员恐怖故事。在 72 小时内,收到了 300 条留言。其中大多数都涉及本章所述的方法导致文件丢失。有趣的是,这些都是经验丰富的 Unix 用户,他们本应更为谨慎。更奇怪的是,尽管这些消息中报告了数百万美元的损失,但当 Unix 被批评“不够用户友好”时,绝大多数系统管理员却站出来为 Unix 辩护。
用户不友好?Unix 甚至都不是“系统管理员友好”!例如:
日期:1988 年 9 月 14 日 星期三 01:39 EDT
收件人:RISKS-LIST@kl.sri.
主题:回复:“单击键”
在 Unix 上,即使是有经验的用户也可能因为
rm
造成很大破坏。我从未费心写过安全的rm
脚本,因为我不会误删文件。然后有一天,我倒霉地敲了!r
来重复历史命令列表中的某条命令,惊恐地看到屏幕回显rm -r *
——那是我之前在另一个目录下执行过的命令,那个目录我花时间清理过。也许 C shell 可以增加一个
nohistclobber
选项?这仍然是我唯一一次误删或覆盖文件,而且这完全是个最低级别的意外陷阱!巧合的是,就在前几天,我听到一个天真的用户对运行
rm *
删除了他刚刚从邮件中错误创建的文件“*”的恐惧。所幸,按字母顺序排得靠前的文件没有写权限,所以删除操作很快就停止了。
这条信息的作者建议通过给 shell 添加选项“nohistclobber”(禁止历史命令覆盖)来进一步修改,以弥补操作系统对星号名称展开机制的根本缺陷。不幸的是,这种“修补”就像用一层新油漆来修复受水损坏的墙壁,效果差强人意。
可预测的命令共享选项名称,参数顺序大致相同,并且在可能的情况下产生类似的输出。保持一致性需要某个中央机构集中精力制定标准。Macintosh 上的应用程序之所以一致,是因为它们遵循苹果发布的一本指导手册。而 Unix 工具则从未有过这种机构。因此,有些工具的选项前面带有短横线(-
),有些则没有;有些读取标准输入,有些则不;有些写入标准输出,有些则不;有些创建的文件是全局可写的,有些则不是;有些报告错误,有些不报告;有些选项与文件名之间有空格,有些没有。
Unix 最初是一次实验,旨在构建一款尽可能简洁干净的操作系统。作为实验,它成功了,但作为生产系统,AT&T 的研究人员逾越了他们的目标。为了让更多人能够使用,操作系统必须功能丰富。如果系统本身不提供这种基本的丰富性,用户就会在底层框架上添加功能。Dave Mankins 认为,Unix 的一致性和可预测性问题的根本原因,可能是它没有为 AT&T 以外的程序员提供用于扩展的知识框架。
日期:1989 年 3 月 4 日 星期六 19:25:58 EST
收件人:Unix 痛恨者
主题:Unix 软蛋们的自娱自乐
Unix 软蛋们喜欢吹嘘每个命令的概念简单性。大多数人可能认为是子程序的东西,Unix 软蛋却把它们包成完整命令,带有自己的参数语法和选项。
这并非完全是蠢主意,因为在没有其他解释器的情况下,通过将这些小子程序连接起来,可以写出相当强大的程序。
可惜没人想到把这些命令做成真正的子程序,这样你就可以把它们链接到自己的程序中,而不用自己写正则表达式解析器(这也是为什么
ed
、sed
、grep
和各种 shell 对正则表达式的理解相似但又略有不同的原因)。Unix 审美的最高成就就是拥有一款只做一件事且做得很好的命令。纯粹主义者反对的是,在伯克利的初级程序员折腾过之后,用于将多个文件连接输出 的程序
cat
现在有了选项。(正如 Rob Pike——也许是终极 Unix 极简主义者所说:“Cat 从伯克利回来时挥舞着旗帜。”)这种哲学在业余者手中,导致了令人难以理解且令人昏昏欲睡的混乱,比如有两款程序
head
和tail
,它们分别打印文件的开头部分或结尾部分。尽管它们的操作是互补的,但head
和tail
是不同的程序,由不同作者编写,并且选项也不同!
如果热力学定律在这里适用,那么 Unix 就会像其他那些随着时间慢慢堆积演化的系统一样,拥有同样缺乏一致性的结构和相同程度的熵,也不会比它们更好或更差。然而,架构上的缺陷却进一步加剧了混乱和意外的程度。特别是,程序被禁止访问调用它们的命令行,以防它们“自燃”。Shell 充当了中介的角色,根据用户的输入对命令行进行清洗和重构。不幸的是,Shell 的表现更像克鲁索探长(Inspector Clouseau),而不是弗洛伦斯·南丁格尔(Florence Nightingale)。
我们提到过,Shell 会执行通配符展开操作,也就是说,它会将星号(*
)替换成目录中所有文件的列表。这是缺陷一:程序本应调用一个库来执行通配符展开。
按照约定,程序会把选项作为第一个参数,通常前面带一个短横线(-
)。这是缺陷二:选项(开关)和其他参数本应是不同的实体,就像在 VMS、DOS、Genera 和其他许多操作系统中一样。
最后,Unix 的文件名几乎可以包含任何字符,包括不可打印字符。这是缺陷三。
这些架构决策之间会产生糟糕的相互作用。当 Shell 在展开 *
时,它会按字母顺序列出文件名,而短横线(-
)在这种字典顺序的等级制度中排在最前。因此,当使用 *
时,以短横线开头的文件名会最先出现。这些文件名会被当作传递给程序的选项,从而导致不可预测、令人惊讶,甚至危险的行为。
日期:1990 年 1 月 10 日 星期三 10:40 CST
主题:回复:
rm *
新闻组:alt.folklore.computers
还有一名可怜学生的故事,他的主目录里正好有一个名为
-r
的文件。他想要删除所有非目录文件(我猜是这样),于是他输入了:……没错,它确实删除了除了那个可爱的
-r
文件以外的所有东西……幸运的是,我们的备份系统还算不错。
有些 Unix 受害者把这个“将文件名当成选项”的 bug 变成了一个“特性”,通过在目录中放一个名为 -i
的文件来实现。输入 rm *
时,shell 会将其展开为 rm -i 文件名列表
,理论上它会在删除每个文件前请求确认。这个解决方案倒也不坏——前提是你不介意在每个目录里都放一个名为 -i
的文件。
也许我们应该修改 mkdir 命令,让它自动创建这个 -i
文件。然后再修改 ls
命令,使它不显示它。
我们认识好几个人,在重命名文件时打错字,结果创建了一个以破折号开头的文件名:
现在试着把它改回来:
这个文件名在其他 Unix 命令中并不会出问题,因为 Unix 命令之间几乎没有一致性。例如,文件名“-文件 2”对 Unix 的“标准文本编辑器”ed 来说是完全合法的。下面这个例子就能正常工作:
但即使你把文件另存为其他名字,或者决定彻底放弃这个文件、只想把它删掉,你的困境依然存在:
rm 会将文件名的第一个字符(破折号)解释为命令行选项;然后它会抱错字符“l”和“e”不是合法的选项。一个文件名以连字符开头——尤其是在这个破折号是通配符匹配的结果时——却被当作一连串选项来看待,这难道不有点疯狂吗?
Unix 提供了两种彼此独立且不兼容的临时“黑科技”方法,用来删除这个命名错误的文件:
rm 的 man 手册中说明,一个单独的破折号位于 rm 命令和其第一个文件名之间时,会让 rm 把所有后续的破折号都当作文件名,而不是选项。但不知出于什么原因,rm 和它的近亲 mv 的用法说明中都没有列出这个“特性”。
当然,用破折号来表示“请忽略所有后续破折号”的做法,并不是通行的惯例,因为命令解析是每个程序各自处理的,并没有使用统一的标准库。像 tar
这样的程序,会用破折号来表示标准输入或标准输出。而其他一些程序则干脆无视它:
Unix 命令经常给出看似合理的结果:只有当你尝试去使用它们时,你才会意识到它们实际上是多么荒谬。
这里有个逗乐和取悦你朋友的方法(感谢 Leigh Klotz 提供)。
首先,悄悄地做以下操作:
然后把这些咒语的结果展示给你的“受害者”看:
最后,为了获得真正的快乐,试试这个:
(提示:按三次 Ctrl-D 就能返回提示符!)
人们投票选总统的次数比阅读印刷文档的次数还多。唯一真正起作用的文档,是那些在线上、只需按一个按键或点击鼠标即可获得的内容。Unix 文档的现状,以及其严重不足的程度,在本书中有专门一章讨论,这里我们仅指出 Unix 的 man 系统在最需要帮助的地方——新手用户面前——表现最差。
并非所有命令都是平等的:有些是由 shell 调用的独立程序,有些则是内置于 shell 中的命令。部分命令有自己的 man 页面,而有些则没有。Unix 期望你知道它们的区别。例如,wc
、cp
和 ls
是 shell 之外的程序,有对应的 man 页面;但 fg
、jobs
、set
和 alias
(这些名字哪来的?)则是 shell 内置命令,因此没有自己的 man 页面。
新手在被告知用“man 命令”查看文档时,很快会感到困惑,因为有些命令有文档,有些则没有。如果她使用的 shell 和第三方书籍中介绍的不同,想要理解更是难上加难,除非去请教专家。
新手难免会出错,要么用了错误的命令,要么使用了正确的命令却带了错误的选项和参数。计算机系统必须能够检测这些错误并反馈给用户。不幸的是,Unix 程序很少这样做。相反,Unix 似乎刻意让错误相互叠加,最终导致致命后果。
在上一节中,我们展示了用 rm
命令不小心删除文件是多么容易。但你可能没有意识到,不用 rm
命令,也同样很容易删除文件。
某些版本的 cc 编译器经常会“坑”本科生,在检查输入文件的明显问题之前就删除之前的输出文件。
日期:1992 年 11 月 26 日 星期四 16:01:55 GMT
主题:求助!
新闻组:cs.questions9
机构:计算机科学基础实验室,
英国爱丁堡
我刚才执行了:
而不是:
不用说,我丢了文件
doit.c
。有没有办法能找回来?(从今天早上开始这个文件经过了大量修改)。
:-(
其他程序也表现出类似行为:
收件人:UNIX 痛恨者
日期:1993 年 7 月 1 日 星期四 09:10:50 -0700
主题:被
tar
和羽毛伺候了经过多次尝试,我终于通过一条不稳定的欧洲链路
ftp
下来了这个 3.2MB 的文件。现在要解压它。我输入:
…却没有任何反应。
哎呀。
是用
c
而不是x
吗?是的。
tar
因为没有指定文件而报错了吗?没有。
tar
发现问题了吗?没有。
tar
真的是没有打包任何文件吗?是的。
tar
覆盖了tar
文件变成了垃圾吗?当然,这就是 Unix。
我要不要再浪费 30 分钟从欧洲重新下载这个文件?
当然,这就是 Unix。
太神奇了。我确信这个设计缺陷已经让很多人吃过亏。有很多简单的方法可以避免这种损失:错误报告、文件版本号、二次确认用户是否真的要覆盖已有文件,等等。感觉他们就是故意努力营造这种损失。
这个漏洞尤其严重地影响那些使用 tar
来备份系统的系统管理员。不止一个系统管理员在备份脚本中写成了 tar xf …
而不是 tar cf …
。
这是一个诚实的错误。磁带在旋转。系统管理员几乎不会怀疑 tar
实际上是在尝试从磁带读取指定的文件,而不是把它们写入磁带。事实上,一切看似都在按计划进行,直到有人真正需要恢复某个文件。然后,惊喜来了:备份根本不是备份。
由于几乎没有错误检查,许多“程序员的工具”给高级用户提供了多种丢失重要信息的可能。
日期:1992 年 10 月 4 日 星期日 00:21:49 PDT
收件人:Unix 痛恨者
主题:这么多混蛋可以选择……
我有个程序,叫 foo,持续运行在我的机器上,提供网络服务,并且每 24 小时检查点保存其(庞大)内部状态。
我切换到包含该程序运行版本的目录,由于这不是程序的开发目录,我好奇到底运行的是哪个版本的代码。该代码用 RCS 维护,所以我自然尝试输入:
以查看可执行文件中包含了哪些源文件的版本。[别管 RCS 明显不合适,或者
ident
的工作方式极其野蛮;我还有更重要的事……]当然,这次我打错了字,因为手指自动反应,更喜欢单词
indent
而不是无意义的ident
:结果,
indent
是 UNIX 那个脑残的 C 代码格式化工具的名字。写这个烂东西的混蛋有没有考虑检查它的输入是否是 C 文件(比如,天啊,检查文件名是不是以.c
结尾)?我想你已经知道答案了。更进一步,这个混蛋还决定,如果给indent
只传一个参数,那你一定是想直接在源文件上做格式化,覆盖旧文件内容。不过别担心,混蛋知道你可能担心这么做会破坏文件,所以它会保存一份旧内容的备份到
foo.BAK
。它是直接把foo
重命名成foo.BAK
吗?当然不是,它傻乎乎地把foo
的所有内容复制到foo.BAK
,然后截断foo
文件,再写入新的格式化代码。混蛋。
你现在应该明白这个故事的重点了……
当一款 Unix 程序运行时,如果它正在从它的可执行文件分页(paging out),你要是乱动文件的各个部分,它会非常生气。特别是它会崩溃,且无法恢复。我因此丢失了程序 20 小时的状态变更。
当然,那些设计(咳)Unix 的混蛋们根本不关心像版本化文件系统这种复杂东西,否则我的命就能救回来了。那些混蛋们也根本想不到要锁定任何你当前正在分页的文件,对吧?
混蛋这么多,干脆全杀了算了?
Pavel
想象一下,如果有一种外墙油漆,在干燥时会释放氯气。根据说明,在外面用没问题,但你如果用它来粉刷卧室,可能会因此丧命。你觉得这种油漆能在市场上撑多久?肯定撑不到 20 年。
当服务员把一盘满是碟子的托盘掉到地上时,你会笑吗?Unix 粉丝会笑。
他们总是第一个嘲笑那些无助的用户,试图理解那些根本和他们刚输入的内容无关的错误信息。
有人把 Unix 中一些荒谬的错误信息当作笑话发布出来。以下这些 Unix 双关语在 Usenet 上传播,没有署名作者。它们适用于 Csh。
这些幽默尝试适用于 Bourne shell:
我们描绘了一幅相当惨淡的画面:晦涩难懂的命令名称、不一致且不可预测的行为、缺乏对危险命令的保护、勉强及格的在线文档,以及对错误检查和健壮性的松懈态度。访问 Unix 之家的人不会有愉快的体验。他们像是第三世界联合国救援任务的访客,而不是迪士尼乐园的游客。Unix 是怎么变成这样的?部分原因是历史因素,正如我们已经指出的。但答案还有另一部分:多年来构建和扩展 Unix 的人的文化。这种文化被称为“Unix 哲学”。
Unix 哲学并不是贝尔实验室和 Unix 系统实验室发布的书面建议,它是一种自由流动的道德准则。不同作者列举了它的不同属性。Don Libes 和 Sandy Ressler 在《Life with Unix》(Prentice Hall,1989)一书中对此做了特别好的总结:
小即美。
10% 的工作解决了 90% 的问题。
面对选择时,选择更简单的方案。
根据对 Unix 程序和工具的经验观察,更准确地总结 Unix 哲学是:
小程序比功能齐全或正确的程序更受欢迎。
粗制滥造完全可以接受。
面对选择时,选择逃避。
Unix 并没有哲学,只有一种态度。那种态度认为,简单且半途而废的工作比复杂且执行良好的工作更有价值。那种态度宣称程序员的时间比用户的时间更重要,即使每个程序员对应成千上万的用户。它是一种赞美最低公分母的态度。
日期:1989 年 12 月 24 日 星期日 19:01:36 EST
来自:David Chapman <zvona@ai..mit.edu>
收件人:Unix 痛恨者
主题:终止作业;Unix 设计范式。
我最近学会了如何在 Unix 上终止作业。在此过程中,我学到了很多关于 Unix 的智慧和强大之处,想和你们分享。
当然,你们大多数人并不使用 Unix,所以知道如何终止作业可能没什么用。然而,像我这样的一些人可能会偶尔运行 TeX 作业,这种情况下,知道如何终止作业就至关重要。无论如何,“kill”命令背后的设计原则在整个 Unix 中被严格应用,所以这条信息可能更具普遍意义。
Unix 允许你用 ^Z 挂起一个作业,或用 ^C 退出并终止。然而,LaTeX 会捕获 ^C。结果,我过去经常堆积几十个 LaTeX 作业。这倒不是真的让我困扰,但我觉得还是学会如何清理它们比较邻里友好。
大多数操作系统都有“kill”命令,Unix 也有。在大多数操作系统中,
kill
命令终止一个进程。而 Unix 的实现更加通用:“kill”命令向进程发送消息。这体现了第一个 Unix 设计原则:
通过使操作完全通用来赋予用户权力。
kill
命令非常强大;它允许你向进程发送各种消息。例如,你可以向进程发送一个让它自我终止的消息,这个消息是-9
。-9
当然是最大的单数字消息,这体现了另一个重要的 Unix 设计原则:
选择反映功能的简单名称。
据我所知,在所有其他操作系统中,没有参数的
kill
命令会终止当前作业。然而,Unix 的kill
命令总是需要一个作业参数。这个明智的设计选择体现了另一个明智的设计原则:
通过要求长命令和危险操作的确认,防止用户意外搞砸自己。
这个原则在 Unix 中的应用极为广泛且文档完善,这里我就不详细说明了,只是顺便提及 Unix 中的注销和文件删除实现。
在我所知的所有其他操作系统中,
kill
命令的作业参数是作业名称。这是一个不充分的接口,因为你可能会有多个 LaTeX 作业(例如),它们的名字都是“latex”,因为它们都是 LaTeX 作业。因此,kill -9 latex
会产生歧义。像大多数操作系统一样,Unix 有一个列出你作业的命令,助记符叫“jobs”。
jobs
命令的输出大致如下:这让你很容易将特定的 LaTeX 作业与作业号对应起来,作业号显示在方括号内。
如果你的思维受到设计不佳操作系统的影响,你可能会认为
kill -9 1
会终止列表中的第 1 号作业。但你会发现它实际上会给你一个友好的错误信息:
kill
命令正确的参数是进程 ID。进程 ID 是像 18517 这样的数字。你可以用“ps”命令找到作业的进程 ID,“ps”命令会列出作业及其进程 ID。找到正确的进程 ID 后,你只需:注意 Unix 会先给你提示符,然后才告诉你作业已经被终止。(用户输入会出现在以“[1]”开头的行之后。)这体现了另一个 Unix 设计原则:
只告诉用户他需要知道的信息,并且不要提前告诉。不要用多余信息增加用户的认知负担。
希望这个小练习对你有所启发。我从学习中深刻体会到 Unix 的设计哲学。Unix
kill
命令的优雅、强大和简洁应该成为我们所有人的一课。
发件人:(Dave Jones)
发件人:
发件人:Phil Agre
来自:(Randal L. Schwartz)
发件人:Matthew P Wiener
发件人:
发件人:(Kees Goossens)
发件人:(Tommy Kelly)
发件人:Daniel Weise
来自:Pavel Curtis