如何开发命令行程序

http://blog.csdn.net/luckheadline

一. 命令行规范

关于实现命令行参数, C 语言有着由来已久的传统规范。

1. 可选命令行参数前有一个“ - ”, DOS WINDOWS 系统也可以用“ / ”。

2. 多个可选命令行参数之间没有顺序要求,每个参数都可以放置在参数列表中的任何位置。

3. 可选命令行参数本身可能会带有参数。

4. 可能有些命令行程序并不遵从以上的规范,虽然这样做并不推荐。

 

 

二. 如何实现命令行参数处理(以 C 语言为例)

    命令行参数总是表现为一个字符串数组,这个字符串数组被称为 ”argv”( 代表 arguments values), 还有一个整数 argc( 代表 arguments count) 用来表示命令行参数列表中参数的个数。因此,我们的 main 函数的格式如下:

        int main(int argc, char* argv[]), 务必要记住 argv[0] 是程序的名字,在 usage 声明中你可能会用到它。 main 函数中的第一任务是实现可选参数,操作 argv 的标准方式如下所示:

 

 

  1. int  i;
  2. int  quiet=0;  //Value for the “-q” optional argument.
  3. for  (i = 1; i < argc; i ++)  //skip argv[0].
  4. {
  5. /*
  6.  *Use the ‘strcmp’ function to compare the argv values to a string
  7.  *of your choice(here, it’s a *optinal argument “-q”). When
  8.  *strcmp returns 0, it means that the two strings are identical.
  9. */
  10.      if  (strcmp(argv[i], “-q”) == 0)  //Process optional arguments
  11.     {
  12.         quiet = 1;  //This is used as a Boolean value.
  13.     }
  14.      else
  15.     {
  16.          //Process non-optional arguments here.
  17.     }
  18. }

请注意,正如这段代码所示,可选参数“

-q ”可以被放置于参数列表的任何位置而且程序都可以正常 work 如果可选参数本身还有参数的话,那么代码将更加的 trickier

 

 

 

  1. int  i;
  2. int  opt = 0;
  3. int  optarg1 = 0;
  4. int  optarg2 = 0;
  5. for  (i = 1; i < argc; i ++)
  6. {
  7.      if  (strcmp(argv[i], “-opt”) == 0)
  8.     {
  9.         opt = 1;  //This is used as a boolean value.
  10.          /*
  11.          *The last argument is argv[argc -1]. Make sure there
  12.          *are enough arguments.
  13.         */
  14.          if  (i + 2 <= argc - 1)  //There are enough arguments in argv.
  15.         {
  16.              /*
  17.              *Increment ‘i’ twice so that you don’t check
  18.              *these arguments the next time through the loop.
  19.             */
  20.             i ++;
  21.             optarg1 = atoi(argv[i]);  //Convert string to int
  22.             i ++;
  23.             optarg2 = atoi(argv[i]);
  24.         }
  25.          else
  26.         {
  27.              //Print usage statement and exit.
  28.         }
  29.     }
  30.      else
  31.     {
  32.          //Process non-optional arguments here.
  33.     }
  34. }

    在很多情况下,命令行处理可能会非常麻烦,不过上面的代码已经可以应付相当多的情况了。

 

 

BTW, Linux 下,习惯上会有两种形式的命令行参数,一种是短形式,通常由 ”-” 加一个字母组成,这种形式的好处是便捷;另一种是长形式,通常由 ”--” 加一个单词组成,这种形式的好处是形象,好记,直观。

 

 

 

三. Usage 声明

有时候,用户可能会输入不合法的命令行参数,你的程序需要处理这种情况以避免程序 crash 。这种情况的正确处理方式是:

1.   显示 usage 声明

2.   退出程序

例如,假设你的程序除了程序名还期望有 3 个参数,并且要接受另外一个可选参数:

usage 声明的以下几点意见:

 

 

 

1. usage 信息 : 总是使用“ usage ”开头,接着是程序名和参数名。参数名应该尽可能的指明参数的意义,比如上面的 filename 。参数名不应该包含空格!可选参数使用 [] ,比如上面程序中的 ”-w” 。非可选参数不要使用 [] !总是打印 stderr ,而非 stdout ,以指明程序没有正确 invoke

2. 程序名:总是使用 argv[0] 以指明程序名而非显式的指出。因为这样,当你重新命名程序之后,不用重写代码。

3. 退出程序:使用 exit 函数( exit 函数被定义在头文件 <stdlib.h> )。 exit 函数的任何非零参数都标志着程序的非正常结束( exit 0 )标识程序的正常执行,但你很少会像这样用)。你也可以使用宏 EXIT_FAILURE EXIT_SUCCESS 以取代 1 0 作为 exit 函数的参数。

如果不得不多次写 usage 声明,你可以将它分离出来作为一个独立的函数,并且将程序名( argv[0] )作为参数传给它。那样它就可以被 main 函数在任何需要的时候调用了。

 

四. 常见错误

1. 当程序接收到不正确参数时,应该总是打印一个 usage 消息给 stderr 。如果处理失败将会自动 redo

2. 不要假设可选参数会固定放在参数列表的某个位置上。

3. 如果不方便的话,就不要尝试一遍处理所有的命令行参数。

4. 不要修改 argv 数组。

 

五. getOpt() 的使用

getOpt() 是一个专门设计来减轻命令行处理负担的库函数。它位于 unistd.h 系统头文件中,其原型如下:

int getopt(int argc, char *const argv[], const char *optstring);

函数给定了命令参数的数量 (argc) ,指向这些参数的数组 (argv) 和选项字符串 (optstring) 后, getopt() 将返回第一个选项,并设置一些全局变量。使用相同的参数再次调用该函数时,它将返回下一个选项,并设置相应的全局变量。如果不再有识别到的选项,将返回 -1 ,此任务就完成了。

getopt() 所设置的全局变量包括:

optarg :指向当前选项参数(如果有)的指针。

optind :再次调用 getopt() 时的下一个 argv 指针的索引。

optopt :最后一个已知选项。

可以重复调用 getopt() ,直到其返回 -1 为止;任何剩下的命令行参数通常视为文件名或称程序相应的其他内容。见以下代码示例:

 

 

 

Unix 程序还支持长选项,可以通过使用 getopt_long() 向程序添加长选项支持,因为 getopt_long() 是同时支持长选项和短选项的 getopt() 版本。 getopt_long() 函数还接受其他参数,其中一个是指向 struct option 对象数组的指针。结构如下:

成员是指向长选项名称(带两个短横线)的指针。 has_arg 成员设置为 no_argument, optional_argument, required_argument (均在 getopt.h 中定义)之一,以指示选项是否具有参数。如果 flag 成员未设置为 NULL ,在处理期间遇到此选项时,会使用 val 成员的值填充它所指向的 int 值。如果 flag 成员为 NULL ,在 getopt_long() 遇到此选项时,将返回 val 中的值;通过将 val 设置为选项的 short 参数,可以在不添加任何其他代码的情况下使用 getopt_long()—— 处理 while loop switch 的现有 getopt() 将自动处理此选项。代码示例可以参见 reference 5

 

 

 

 

 

Reference:

http://www.cs.caltech.edu/courses/cs11/material/c/mike/misc/cmdline_args.html

http://www.ibm.com/developerworks/cn/linux/shell/clutil/index.html

http://linux.chinaitlab.com/command/4198.html

http://www.gnu.org/software/libtool/manual/libc/Getopt.html

http://www.ibm.com/developerworks/cn/aix/library/au-unix-getopt.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章