本文将指导您学习如何编写即使对最终用户而言也足够简单的 Linux 命令行实用程序。本文以概述可靠的命令行最佳实践开始,并以详细地研究一个有效的选页工具结束,为您提供动手编写自己的实用程序所需要的背景知识。
本文演示如何编写与 cat、ls、pr 和 mv 等标准命令类似的 Linux 命令行实用程序。我选择了一个名为 selpg 的实用程序,这个名称代表 SELect PaGes。selpg 允许用户指定从输入文本抽取的页的范围,这些输入文本可以来自文件或另一个进程。selpg 是以在 Linux 中创建命令的事实上的约定为模型创建的,这些约定包括:
独立工作
在命令管道中作为组件工作(通过读取标准输入或文件名参数,以及写至标准输出和标准错误)接受修改其行为的命令行选项。不久前我为一位客户开发了 selpg。随后我将它公布在一个 UNIX 邮件列表上,结果有许多成员告诉我他们发现这是一个有用的工具。
该实用程序从标准输入或从作为命令行参数给出的文件名读取文本输入。它允许用户指定来自该输入并随后将被输出的页面范围。例如,如果输入含有 100 页,则用户可指定只打印第 35 至 65 页。这种特性有实际价值,因为在打印机上打印选定的页面避免了浪费纸张。另一个示例是,原始文件很大而且以前已打印过,但某些页面由于打印机卡住或其它原因而没有被正确打印。在这样的情况下,则可用该工具来只打印需要打印的页面。
除了包含 Linux 实用程序现实的示例外,本文还有以下特性:
它用实例说明了 Linux 软件开发环境的能力。它演示了对一些系统调用和 C 库函数的适当使用,其中包括 fopen、fclose、access、setvbuf、perror、strerror 和 popen。它实现了打算用于通用目的的实用程序(而不是一次性程序)所应有的那种彻底的错误检查。它对潜在的问题提出警告,如在 C 中编程时可能出现的缓冲区溢出,并就如何预防这些问题提供了建议。它演示了如何进行手工编码的命令行参数解析。它演示了如何在管道中以及在输入、输出和错误流重定向的情况下使用该工具。
Linux 命令行准则
通用 Linux 实用程序的编写者应该在代码中遵守某些准则。这些准则经过了长期发展,它们有助于确保用户以更灵活的方式使用实用程序,特别是在与其它命令(内置的或用户编写的)以及 shell 的协作方面 ― 这种协作是利用 Linux 作为开发环境的能力的手段之一。selpg 实用程序用实例说明了下面列出的所有准则和特性。(注:在接下来的那些示例中,“$”符号代表 shell 提示符,不必输入它。)
Linux 命令行准则 1. 输入
应该允许输入来自以下两种方式:
在命令行上指定的文件名。例如:
$ command input_file
在这个例子中,command 应该读取文件 input_file。
标准输入(stdin),缺省情况下为终端(也就是用户的键盘)。例如:$ command
这里,用户输入 Control-D(文件结束指示符)前输入的所有内容都成为 command 的输入。但是,使用 shell 操作符“<”(重定向标准输入),也可将标准输入重定向为来自文件,如下所示:
$ command < input_file
这里,command 会读它的标准输入,不过 shell/内核已将其重定向,所以标准输入来自 input_file。
使用 shell 操作符“|”(pipe)也可以使标准输入来自另一个程序的标准输出,如下所示:
$ other_command | command
这里,other_command 的标准输出(stdout)被 shell/内核透明地传递至 command 的标准输入。
Linux 命令行准则 2. 输出
输出应该被写至标准输出,缺省情况下标准输出同样也是终端(也就是用户的屏幕):
$ command
在这个例子中,command 的输出出现在屏幕上。
同样,使用 shell 操作符“>”(重定向标准输出)可以将标准输出重定向至文件。
$ command > output_file
这里,command 仍然写至它的标准输出,不过 shell/内核将其重定向,所以输出写至 output_file。或者,还是使用“|”操作符,command 的输出可以成为另一个程序的标准输入,如下所示:
$ command | other_command
在这个例子中,shell/内核安排 command 的输出成为 other_command 的输入。 |