设计实用程序
一个不错的经验法则就是当您第二次必须解决某个问题时,首先考虑实用程序的设计。不要对第一次编写的一次性作品感到遗憾;您可以将它看作是一个原型。第二次,请把您所需的功能与第一次所需的功能作比较。在第三次前后,您应该开始考虑花时间来编写一个通用实用程序。即使纯粹的重复性任务也可能会给实用程序的开发带来好处;例如,由于人们对尝试以通用的方式重命名文件感到失望,于是开发了许多通用文件重命名程序。
下面是一些实用程序设计目标;每个目标将在下面单独的小节中介绍。
- 做好一件事情。
- 成为一个过滤器。
- 通用化。
- 健壮。
- 新颖。
做好一件事情
做好一件事情;不要糟糕地做多件事情。关于做好一件事情的最佳例子或许是 sort。除了 sort 外,没有其他 哪个实用程序具有排序功能。基本的思想很简单:如果一次仅解决一个问题,您就能花时间把它解决好。
设想一下,如果大多数程序都具有排序功能,但是有些仅支持按词法排序,而其他一些仅支持按数字排序,另外一些甚至支持关键字选择而不是对整行排序,那将是一件多么令人沮丧的事情。起码,这也是恼人的。
当您发现某个问题需要解决时,应尝试将问题分解为多个部分,不要重复那些其他实用程序中已经存在的部分。您对允许配合现有工具使用的工具关注得越多,您的实用程序就越有可能保持有用。
也许您需要编写多个程序。完成专门任务的最佳途径通常是编写一两个实用程序,再用一些线索将它们联系起来,而不是编写单个程序来解决整件事情。使用 20 行的 shell 脚本来将新的实用程序与现有工具结合起来是很理想的。如果尝试一次解决整个问题,随之而来的第一个变更就可能要求您全盘重新考虑。
我偶尔需要从数据库生成两列或三列的输出。编写一个程序在单个列中生成输出,然后结合使用一个对输出进行分列的程序,这样通常会更有效率。组合这两个实用程序的 shell 脚本本身是临时性的,单独的实用程序比这个脚本的使用寿命更长。
有些实用程序服务于非常专一的需要。针对一个包含大量内容的目录,如果 ls 的输出非常快地滚出屏幕,这可能是因为其中有一个文件具有非常长的文件名,从而迫使 ls 仅对输出使用单个列。使用 more 来对输出分页会花一些时间。为什么不像下面这样就按长度对行排序,然后通过 tail 来管道输出结果呢?
清单 1. 世间能找到的最小实用程序 sl
#/usr/bin/perl -w
print sort { length $a <=> length $b } <>;
|
清单 1 中的脚本确切地就做一件事情。它不接受任何选项,因为它不需要选项;它仅关心行的长度。归功于 Perl 便利的 <> 表达方式,这个小实用程序既适用于标准输入,也适用于命令行指定的文件。