当前位置:操作系统 > Unix/Linux >>

开发Linux命令行实用程序

最佳实践和考虑周全的编码造就可靠的命令行工具

  本文将指导您学习如何编写即使对最终用户而言也足够简单的 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 实用程序的编写者应该在代码中遵守某些准则。这些准则经过了长期发展,它们有助于确保用户以更灵活的方式使用实用程序,特别是在与其它命令(内置的或用户编写的)以及 shell 的协作方面 ― 这种协作是利用 Linux 作为开发环境的能力的手段之一。selpg 实用程序用实例说明了下面列出的所有准则和特性。(注:在接下来的那些示例中,“$”符号代表 shell 提示符,不必输入它。)

  准则 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 的标准输入。

  准则 2. 输出

  输出应该被写至标准输出,缺省情况下标准输出同样也是终端(也就是用户的屏幕):

  $ command

  在这个例子中,command 的输出出现在屏幕上。

  同样,使用 shell 操作符“>”(重定向标准输出)可以将标准输出重定向至文件。

  $ command > output_file

  这里,command 仍然写至它的标准输出,不过 shell/内核将其重定向,所以输出写至 output_file。

  或者,还是使用“|”操作符,command 的输出可以成为另一个程序的标准输入,如下所示:

  $ command | other_command

  在这个例子中,shell/内核安排 command 的输出成为 other_command 的输入。

  准则 3. 错误输出

  错误输出应该被写至标准错误(stderr),缺省情况下标准错误同样也是终端(也就是用户的屏幕):

  $ command

  这里,运行 command 时出现的任何错误消息都将被写至屏幕。

  但是使用标准错误重定向,也可以将错误重定向至文件。例如:

  $ command 2>error_file

  在这个例子中,command 的正常输出在屏幕显示,而任何错误消息都被写至 error_file。

  可以将标准输出和标准错误都重定向至不同的文件,如下所示:

  $ command >output_file 2>error_file

  这里,将标准输出写至 output_file,而将所有写至标准错误的内容都写至 error_file。

  如果已将标准输出重定向至某一位置,也可以将标准错误重定向至同一位置。例如:

  $ command 2>&1

  在这个例子中,符号“2>&1”表示“将标准错误发送至标准输出被重定向的任何位置”,因此错误和正常的消息都将在屏幕上显示。当然,这是多余的,因为下面简单的调用

  $ command

  将做同样的事。在标准输出已被重定向至其它源,而您希望在同一命令行上将标准错误也写至同一目的地时,该特性就非常有用。例如:

  $ command >output_file 2>&1

  在这个例子中,已首先将标准输出重定向至 output_file;因此“2>&1”将使标准错误也被重定向至 output_file。

  准则 4. 执行

  程序应该有可能既独立运行,也可以作为管道的一部分运行,如上面的示例所示。该特性可以重新叙述如下:不管程序的输入源(文件、管道或终端)和输出目的地是什么,程序都应该以同样的方式工作。这使得在如何使用它方面有最大的灵活性。

  准则 5. 命令行参数

  如果程序可以根据其输入或用户的首选参数有不同的行为,则应将它编写为接受名为选项的命令行参数,这些参数允许用户指定什么行为将用于这个调用。

  作为选项的命令行参数由前缀“-”(连字符)标识。另一类参数是那些不是选项的参数,也就是说,它们并不真正更改程序的行为,而更象是数据名称。通常,这类参数代表程序要处理的文件名,但也并非一定如此;参数也可以代表其它东西,如打印目的地或作业标识(有关的示例,请参阅“man cancel”)。

  可能代表文件名或其它任何东西的非选项参数(那些没有连字符作为前缀的)如果出现的话,应该在命令的最后出现。

  通常,如果指定了文件名参数,则程序把它作为输入。否则程序从标准输入进行读取。

  所有选项都应以“-”(连字符)开头。选项可以附加参数。

  Linux 实用程序语法图看起来如下:

  $ command mandatory_opts [ optional_opts ] [ other_args ]

  其中:

  command 是命令本身的名称。

  mandatory_opts 是为使命令正常工作必须出现的选项列表。

  optional_opts 是可指定也可不指定的选项列表,这由用户来选择;但是,其中一些参数可能是互斥的,如同 selpg 的“-f”和“-l”选项的情况(详情见下文)。

  other_args 是命令要处理的其它参数的列表;这可以是任何东西,而不仅仅是文件名。

  在以上定义中,术语“选项列表”是指由空格、跳格或二者的结合所分隔的一系列选项。

  以上在方括号中显示的语法部分可以省去(在此情况下,必须将括号也省去)。

  各个选项看起来可能与下面相似:

  -f (单个选项)

  -s20 (带附加参数的选项)

  -e30 (带附加参数的选项)

  -l66 (带附加参数的选项)

  有些实用程序对带参数的选项采取略微不同的格式,其中参数与选项由空格分隔 ― 例如,“-s 20” ― 但我没有选择这么做,因为它会使编码复杂化;这样做的唯一好处是使命令易读一些。

  以上是 selpg 支持的实际选项。

  selpg 程序逻辑

  如前面所说的那样,selpg 是从文本输入选择页范围的实用程序。该输入可以来自作为最后一个命令行参数指定的文件,在没有给出文件名参数时也可以来自标准输入。

  selpg 首先处理所有的命令行参数。在扫描了所有的选项参数(也就是那些以连字符为前缀的参数)后,如果 selpg 发现还有一个参数,则它会接受该参数为输入文件的名称并尝试打开它以进行读取。如果没有其它参数,则 selpg 假定输入来自标准输入。

  参数处理

  “-sNumber”和“-eNumber”强制选项:

  selpg 要求用户用两个命令行参数“-sNumber”(例如,“-s10”表示从第 10 页开始)和“-eNumber”(例如,“-e20”表示在第 20 页结束)指定要抽取的页面范围的起始页和结束页。selpg 对所给的页号进行合理性检查;换句话说,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,