有些程序可能合法地读取一种格式的记录,但是却产生完全不同的输出 。这样的一个例子就是将输入材料划分为列的实用程序 。这样一个实用程序可能将输入中的行视为记录,但是却在输出中的每行上产生多个记录 。
并非每个实用程序都完全符合这个模型 。例如,xargs 不是接受记录而是接受文件名作为输入,并且所有的实际处理都是由其他程序完成的 。
通用化
尝试将任务看作与您实际执行的任务类似;如果您能找出这些任务的通用描述,那么最好尝试编写一个符合该描述的实用程序 。例如,如果您发现自己一天在根据词法对文本排序,而另一天在根据数字对文本排序,那么考虑编写一个通用排序实用程序也许是有意义的 。
对功能进行通用化有时会导致您发现:某个看起来似乎像单个实用程序的程序,实际上却是配合起来使用的两个实用程序 。这很好 。编写两个设计良好的实用程序可能要比编写一个丑陋的或复杂的实用程序更容易 。
做好一件事情并不意味着 仅仅 做一件事情 。它意味着处理一致但有用的问题空间 。许多人都使用 grep 。然而,它的大量效用在于执行相关任务的能力 。grep 的各种选项完成许多小实用程序的工作,如果这些工作都由单独的小实用程序来完成,最终会造成大量共享的、重复的代码 。
这条规则,以及做好一件事情的规则,都是一个根本原理的必然结果:无论何时都要尽可能避免代码重复 。如果您编写半打程序,其中每个都对行排序,您最终可能必须六次修复六个类似的 bug,而不是去使用一个得到更好维护的 sort 程序 。
这是编写实用程序的一部分,即把大多数工作添加到完成该实用程序的过程中 。您也许没有时间在最初就完全通用化一个实用程序,但是当您一直使用该实用程序就会获得相应的回报 。
有时,向某个程序添加相关功能是很有用的,即使这个功能并不是用来完成完全相同的任务 。例如,当运行在终端设备上时,对原始二进制数据进行完美打印的程序可能更为有用,因为它使终端进入原始模式 。这样使得测试涉及键盘映射、新键盘等的问题变得容易多了 。不确定为什么当您按 delete 键时却得到代字号(~)吗? 这是弄清实际发送了什么内容的容易途径 。这并不是完全相同的任务,但它足够类似,因而可能成为一个附加特性 。
清单 2 中的 errno 实用程序就是通用化的很好例子,因为它同时支持数字和符号名称 。
健壮
实用程序的稳定性是很重要的 。容易崩溃或无法处理真实数据的实用程序不是有用的实用程序 。实用程序应该能够处理任意长度的行、巨型文件,等等 。实用程序无法处理超过其内存容量的数据集或许是可以容忍的,但是有些实用程序不是这样;例如,sort 通过使用临时文件,一般能够对比其内存容量大得多的数据集排序 。
应该尽量确保弄清楚您的实用程序可能要操作哪些数据 。不要简单地忽略无法处理的数据的可能性 。应该检查这种情况并诊断您的实用程序 。错误消息越明确,您对用户就越有帮助 。尽量给用户提供足够的信息,以便让他们知道发生了什么情况以及如何解决 。当处理数据文件时,尽量准确识别出不良的数据 。当尝试解析数字时,不要简单地放弃;应该告诉用户您得到了什么数据,而且如果可能的话,还应该告诉用户该数据位于输入流中的哪一行上 。
作为一个很好的例子,请考虑 dc 的两种实现之间的区别 。如果您运行 dc /home ,其中一种实现会显示“Cannot use directory as input!”而另一种实现只是无声地返回,没有错误消息,也没有不寻常的退出代码 。当您错误地键入一个 cd 命令时,您更希望当前路径中有哪一种实现呢?类似地,如果您提供某个目录中的数据流(或许是执行 dc
推荐阅读
- 安装显卡好简单
- lilo/grub linux忘记了密码怎么办
- vmware 配置实例-linux host + windows guest + fire
- Linux 内核的类型
- 其它 Linux 常用命令
- 改变文件或目录的访问权限 Linux 常用命令
- 备份与压缩 Linux 常用命令
- 在Linux环境下运行DOS命令 Linux 常用命令
- 入门:Linux 2.6 内核的嵌入式系统应用
- 安装过Windows的电脑上如何安装Linux