彩摘网>快讯>正文

cat命令的源码进化史

2019-02-06 20:04:48 产品中国 分享

有一次,我跟我的亲戚有一场争论,是关于读一个计算机科学的学位是否值得。当时是我在大学里面临是否选择计算机科学专业的时候。我姑姑和一个表哥认为我不该选。他们觉得会编程当然是个既有用又合算的事情,但是他们也坚信,计算机科学更新太快了,当下学到的知识会很快被淘汰掉。所以最好是选一门编程的课程,然后主修经济或者物理这种基本知识一辈子都适用的专业。

我并不相信他们的理论,并且选择了主修计算机专业(抱歉了姑姑和表哥!)其实不难看出,为什么常人会认为计算机科学,或者软件工程这样的专业,每几年就会更新换代。先是诞生了私人计算机,然后是网络,手机,机器学习……科技永远在变化,那么其潜在的技术原理当然也在变化了。当然,最让人惊讶的是,这些基础技术原理,其实基本没变。我相信大部分人要是知道他们计算机中重要软件到底有多老,肯定会震惊。我并不是说软件的表面,毕竟我自己用的最多的火狐浏览器,两周前才更新过。但是如果你打开帮助手册查看grep之类的工具,你会发现它的上一次更新还是在2010年(至少Mac系统是这样)。grep的初代诞生于1974年,那时候的计算机时代好比侏罗纪。现如今,人们(以及程序)在工作中仍然要依赖grep做很多事情

我姑姑和表哥把计算机科技想象成一系列沙滩上的城堡,涨潮时潮水抹去旧的城堡,更加华丽的新城堡又会被建成。其实在现实中的很多领域,我们都是不断地在现有的程序基础上进行迭代。我们也许会时不时的修改这些程序来避免软件崩溃,但是除此之外这些程序不需要额外的维护。grep是一个简单的程序,它所解决的问题现在也有意义,所以它至今还存在。很多应用程序的编写都起始于一个很高的角度,就像是在金字塔顶端的基础上构建,而金字塔本身是由曾经解决问题的答案所建成的。现在看来很陈旧的,三四十年前的想法与概念,在很多时候都融入到了你现在计算机上安装了的应用程序里。

我想仔细研究一个这样的老程序,看看它从诞生到现在到底被修改了多少次,这肯定很有趣。我想用cat这个最简单的Unix工具来作为例子。Ken Thompson在1969年开发了初代cat。如果我跟别人说我计算机里有个1969年的程序,这准确吗?cat在这几十年里到底经历了几次迭代?我们计算机里的程序到底有多古老?

幸好有这个代码仓库,我们可以清晰的了解到从1969年以来,cat是如何进化的。我接下来会主要聚焦于我自己Macbook上cat程序的历史实现方式。你会看到,cat历史从最初的Unix版本,到现在的Mac版本,这个程序被重写了比你预想的还要多的次数-但是最终它所实现的功能几乎跟五十年前一模一样。

Unix实验版本

1969年,Ken Thompson和Dennis Ritchie开始在PDP 7上开发Unix。这是在C语言出现之前,所以早期的Unix程序都是用PDP 7上的汇编语言开发的。他们使用了专门针对于Unix的汇编版本,因为Ken Thompson开发了自己的汇编编译器,他在PDP 7出厂商DEC提供的编译器基础上添加了新的功能。Thompson的改进文档在初始Unix编程手册中有收录,在as, 编译器条目下面。

cat的初代实现使用了PDP 7汇编语言。我有添加一些注释来解释每行命令,但是除非你明白Thompson编写汇编编译器的一些扩展,不然这个程序还是很难理解。这里有两个重要的点。第一,字符;可以被用于分隔同一行的声明语句。根据sys指令的描述,;通常被用于在同一行使用系统调用参数。第二,Thompson添加了数字0-9用于支持“暂存标记”。这些标记可以被整个程序重用,这就像Unix编程手册所描述的,“对于程序员思维和汇编语言字符空间的缩减优化”。从手册中,你可以使用nf来表示下一个标记n;用nb来表示上一个标记n。举个例子,如果你有个标记为1:的代码块,你可以从相距很远的下方代码中使用jmp 1b来往上跳回标记代码。(但是你不能往下跳到标记代码,除非你使用jmp 1f。)

关于初代cat最有意思的是,它包含了两个我们熟知的名字,分别是一个标记为是一个标记为getc,和一个标记为putc的代码块,这表示这俩名字要比标准C语言库都要历史久远。初代cat实际上包含了这两个方法的实现。这样的实现方式使得输入字符可以被写入缓冲区,也就是说,读和写不需要以单个字符为单位完成。

初代cat并没有存在很久。Ken Thompson和Dennis Ritchie成功的劝说了贝尔实验室帮他们购入了一台PDP11,以便于他们对Unix系统进行扩展与提高。PDP 11使用的是一种不同的指令集,因此他们不得不重写cat。对于第二代cat代码我也加了注释。第二代使用了针对于新指令集的新版汇编助记符,也利用了PDP 11中不同的地址模式。(那些源代码中的括号和$符号,是被用来指代不同的地址模式的。)但是cat第二代中也同样使用了初代中的;和暂存标记,这些功能一定是在PDP 11中移植as时,被保留了下来。

cat的第二代源代码远比初代要简洁很多。第二代也更加的”Unix-y”,因为它不再需要一串文件名作为命令参数,而是与如今的cat一样,在没有参数的情况下,从stdin读取输入。对于二代cat,你也可以使用参数-来指定从stdin读取输入数据。

1973年,为了准备发布第四版Unix,很大一部分Unix系统都用C语言重写了一遍。但是C语言版本的cat在Unix发布后过了一段时间才出现。第一个C语言版本的cat只出现在第七版Unix系统中。这个实现方法非常值得一读,因为它非常简单明了。与其他版本比较,这一版最能作为代表cat的K&R C语言教育演示版本。这段程序的核心就是如下两行:

当然还有更多的代码,但是除了这两行以外,剩下的逻辑更多的是在确保用户不会同时读写同一个文件。另一个有意思的地方是,这个版本的cat只认得一个标记,-u。这个-u标记可以被用于关闭输入输出缓冲区,不然cat会默认缓存512字节。

伯克利软件套件/BSD

在第七版之后,Unix催生了各种各样的衍生品。MacOS是基于Darwin系统的,而Darwin是基于伯克利软件套件(BSD),因此BSD是我们最感兴趣的Unix分支。BSD最初是作为Unix附加功能的软件合集,但是它最终成为了一个完整的操作系统。BSD似乎一直在用cat的初代版本,一直到第四版BSD发布为止。第四版BSD也就是4BSD,它添加了对于新标记的支持。4BSD版本的cat能明显的看出是初代的衍生品,不过它添加了一些新的函数用来实现用新标记触发的功能。4BSD文件系统的命名方法是基于fflg这个变量的,fflg用于标记指令的输入是从文件,还是stdin读取的。继fflg之后,nflgbflgvflgsflgeflgtflg也被用于记录程序中的标记是否被用到。这些命令行标记是cat添加的最后一批标记;如今至少在Mac系统中的cat命令行手册有列出来这些标记。4BSD是在1980年发布的,所以这一系列的标记有38岁了。

cat最后一次被重写是为了BSD Net/2,这主要是为了避免软件许可证问题,因此所有AT&T Unix衍生代码都被替换为了新代码。BSD Net/2在1991年发布。最后一次重写是由Kevin Fall完成的,Kevin Fall于1988年毕业于伯克利,之后他花了一年的时间在计算机系统研究院(CSRG)工作了一年。Fall告诉我,用AT&T代码写的Unix工具集列表被挂在了CSRG的一面墙上,员工们被告知可以选择感兴趣的工具重写。Fall选择了catmknod。在如今Mac系统的默认cat版本中,Fall的名字排在开发者名单前列。他所编写的cat,虽然是个很简单的程序,但是直到今年还有数百万的用户在使用。

Fall所写的cat源代码比我们之前看到的版本要长许多。除了支持-?帮助标记,这一版并没有添加新的功能。理论上来说,这一版代码与4BSD版本非常相似。代码之所以长,是因为Fall分开了“旧版”和“新版”的逻辑。“旧版”是典型的cat;它一个字符一个字符的输出。“新版”的cat包括了4BSD命令行选项。这样的分割很有道理,但是使得代码在第一眼看上去比实际复杂很多。代码的最后有个华丽的错误处理方程,这也增加了代码长度。

MacOS

2001年,苹果公司发布了Mac OS X系统。这次发布对于苹果公司来说非常重要,因为他们花了很多年,走了不少弯路,为了研发能够取代存在了很多年的旧版Mac OS系统。苹果公司内部曾经有过两次研发新系统的尝试,但是最终都没能成功;后来,苹果收购了史蒂夫·乔布斯的公司NeXT,他们公司开发了一款名为NeXTSTEP的,基于面向对象编程框架的操作系统。苹果决定使用NeXTSTEP作为Mac OS X的基础。NeXTSTEP的一部分是基于BSD开发的,所以用NeXTSTEP作为Mac OS X的基础,同时也给苹果系统带来了BSD代码风格。

新发布的第一版Mac OS X中包含了来自NetBSD项目的cat代码实现。NetBSD项目如今仍在不断开发中,它最初是来自386BSD的分支。而386BSD是直接基于BSD Net/2的。所以Mac OS X上的cat就是Kevin Fall所写的cat。唯一变化的是,Kevin Fall写的错误处理函数err()被替换成了err.h中的err()err.h是BSD基于C语言标准库的扩展。

声明:本站部分资源来源于网络,版权归原作者或者来源机构所有,如作者或来源机构不同意本站转载采用,请通知我们,我们将第一时间删除内容。本站刊载文章出于传递更多信息之目的,所刊文章观点仅代表作者本人观点,并不意味着本站赞同作者观点或证实其描述,其原创性及对文章内容的真实性、完整性、及时性本站亦不作任何保证或承诺,请读者仅作参考。
编辑: