《UNIX编程环境》——5.9 get和put:追踪文件变动

简介: 程序在开发过程中不断地改正错误和增加新功能。版本追踪往往是不可少的。特别是有的用户把程序移植到其他的机器上使用—他们常常跑回来问“在我们的版本之后又有哪些改动”,或者“这个那个错误是怎么改的”。

本节书摘来自异步社区《UNIX编程环境》一书中的第5章,第5.9节,作者:【美】Brian W. Kernighan , Rob Pike著,更多章节内容可以访问云栖社区“异步社区”公众号查看

5.9 get和put:追踪文件变动

这一节是本章的最后一节,我们将介绍一个更大、更复杂的例子,以此说明shell如何与awk和sed进行合作。

程序在开发过程中不断地改正错误和增加新功能。版本追踪往往是不可少的。特别是有的用户把程序移植到其他的机器上使用—他们常常跑回来问“在我们的版本之后又有哪些改动”,或者“这个那个错误是怎么改的”。保留备份使尝试新思想也变得更加安全稳妥:如果新的程序不成功,利用备份很容易回到原来的程序。

保存所有版本是一种备份方法。然而这样做不易组织,同时占用磁盘空间太多。我们可以利用一个可能性,即相邻两版本间通常大部分是重复不变的,从而只要保存一次即可。用diff -e命令生成一个ed命令列表,可以把老版本转换成新版本:

screenshot

这样,通过维护一个完整的版本,以及把这个版本转换为任何其他版本的一组编辑命令,就可以把文件的所有版本都保留在一个(不同的)文件中。

这种方法有两种组织方式:一种是保留最新的完整版本和转换到老版本的编辑命令,另一种是保留最老的版本和转换到新版本的编辑命令。虽然后一种方式比较容易实现,但是当有很多版本时,前一种方式使用较快,因为我们一般总是对当前版本感兴趣。

我们选择第一种组织方式。在一个我们称之为“历史文件”的文件中,保存当前版本和多组编辑命令,每组编辑命令把某一版本转换为前一版本。各组编辑命令以下一行信息开始:

screenshot

摘要为单行,由个人提供,它描述文件的改动。

有两个维护版本的命令:get和put。get命令从历史文件里获得版本,put命令在得到一个单行的变动摘要后,把一个新的版本放入历史文件中。

在介绍具体实现之前,我们先举例说明get和put如何工作,以及历史文件是怎样维护的:

screenshot

其中“编辑命令”是由2d行命令组成的,表示删除文件的第2行,这样就可以将新版本转换为老版本。

screenshot

编辑命令从上到下编辑历史文件,用来产生所要求的版本:第一组编辑命令把最新的版本转换为次新的版本,下一组命令把次新的版本换成第三新的版本,依此类推。因此,实际上每调用一次ed命令就把文件向老版本推进了一个版本。

如果被修改的文件包含行首为@@@的行,会引起一些麻烦,另外diff(1)命令的BUGS段将对只含一个句号的行给出警告。我们选择@@@作为编辑命令的标题头记号,因为标准正文一般不会用到这种序列。

讨论get和put命令的使用说明和命令的各种不同形式需要很多篇幅,所以我们只给出它们最后的形式。put命令比较简单,其程序为:

screenshot

读完一行摘要之后,put调用get从历史文件中提取前一个版本。get的-o选项表示给出一个不同的输出文件名。如果get找不到历史文件,它返回一个错误状态,而put将创建一个新的历史文件。如果历史文件已经存在,then子句以临时文件的形式创建一个新的历史文件,文件创建依次利用下列内容:最新版本,@@@行,新版本转换为次新版本的编辑命令,以及老的编辑命令和@@@行。最后,用overwrite把临时文件复制到历史文件。

get程序比put程序更复杂,主要是因为有一些选项:

screenshot

这些选项很普通。-i和-o指定输入和输出文件名。-[0-9]选择特定的版本:0表示最新版本(默认值),-1表示次新版本,依次类推。循环while语句,用test和shift实现对全部参数的遍历。循环不用for语句,因为某些选择项(-i、-o)要使用其他参数,所以要用shift把对应参数移出,而位于for循环语句内部的shift语句不能与for很好的合作。ed的“-”选项关闭了在读写文件时通常使用的符号计数功能。

程序

screenshot

(这是我们在put中使用的形式)但是更紧凑,对于熟悉操作符¦¦ 的程序员来说也更清楚。{和}之间的命令表示在当前shell下执行,而不是在子shell下执行;这样就保证了exit是从get退出,而不从子shell退出。字符{和}很像do和done—它们只在分号、换行或命令终止符之后才具有特殊作用。

最后,我们介绍get程序的工作代码。首先,sed把历史文件分成两部分:最新版本和编辑命令集合。然后由awk程序处理编辑命令。最后对@@@行进行计数(但不打印),同时传递编辑命令,直到计数值超过所期望的版本数(回忆一下,awk命令的默认动作是打印输入行)。两个ed命令$d和w附加在历史文件中的命令后:$d删除sed留在当前版本里的@@@行,而w命令完成文件的最后写入。这里不需要overwrite,因为get程序只改变文件的版本,而不改变先前的历史文件。

练习5-29 编写一个命令version,完成下述两件工作:

screenshot

报告摘要,修改日期和修改人,对历史文件中选定版本进行修改。

screenshot

报告9月20日的版本号。这被典型地用于下面命令中(version可以方便地回送历史文件名):

screenshot

练习5-30 修改get和put,使之可以操作其他目录下的历史文件,不至于因为.H文件把工作目录弄乱。

练习5-31 一旦工作完成,不再需要保留所有的文件版本。怎样实现从历史文件中删除一些版本呢?

相关文章
|
5月前
|
Unix 程序员 Linux
【OSTEP】动态内存开辟 | 内存API常见错误 | UNIX: brk/sbrk 系统调用 | mmap创建匿名映射区域 | mmap创建以文件为基础的映射区域
【OSTEP】动态内存开辟 | 内存API常见错误 | UNIX: brk/sbrk 系统调用 | mmap创建匿名映射区域 | mmap创建以文件为基础的映射区域
177 0
|
4月前
|
Unix Linux Shell
在Unix/Linux系统中,文件和目录的权限管理
在Unix/Linux系统中,文件和目录的权限管理
36 3
|
移动开发 Unix Linux
一文搞清UNIX/Linux与Windows文件换行符格式差异
一文搞清UNIX/Linux与Windows文件换行符格式差异
299 0
一文搞清UNIX/Linux与Windows文件换行符格式差异
|
Unix Shell Linux
Unix 设置用户ID和文件访问权限
Unix 设置用户ID和文件访问权限
253 0