现在的位置: 首页 > 综合 > 正文

命令行参数解析(2)

2012年03月08日 ⁄ 综合 ⁄ 共 6274字 ⁄ 字号 评论关闭

6、改变getopt()对错误命令行参数信息的输出行为
不正确的调用程序在所难免,这种错误要么是命令行选项无效,要么是缺少选项参数。正常情况下,getopt()会为这两种情况输出自己的出错信息,并且返回'?'。为了验证此事,可以修改一下上面的清单2中的代码。

  1. 清单3:#include <stdio.h>
  2. #include <unistd.h>
  3. int main (int argc, char **argv)
  4. {
  5. int oc; /*选项字符 */
  6. char *b_opt_arg; /*选项参数字串 */
  7. while((oc = getopt(argc, argv, "ngl:")) != -1)
  8. {
  9. switch(oc)
  10. {
  11. case 'n':
  12. printf("My name is Lyong./n");
  13. break;
  14. case 'g':
  15. printf("Her name is Xxiong./n");
  16. break;
  17. case 'l':
  18. b_opt_arg = optarg;
  19. printf("Our love is %s/n", optarg);
  20. break;
  21. case '?':
  22. printf("arguments error!/n");
  23. break;
  24. }
  25. }
  26. return 0;
  27. }
  28. 输入一个错误的命令行,结果如下:$ ./opt_parse_demo -l
  29. ./opt_parse_demo: option requires an argument -- l
  30. arguments error!

很多时候,我们不希望输出任何错误信息,或更希望输出自己定义的错误信息。可以采用以下两种方法来更改getopt()函数的出错信息输出行为:

在调用getopt()之前,将opterr设置为0,这样就可以在getopt()函数发现错误的时候强制它不输出任何消息。

如果optstring参数的第一个字符是冒号,那么getopt()函数就会保持沉默,并根据错误情况返回不同字符,如下:

“无效选项” —— getopt()返回'?',并且optopt包含了无效选项字符(这是正常的行为)。

“缺少选项参数” —— getopt()返回':',如果optstring的第一个字符不是冒号,那么getopt()返回'?',这会使得这种情况不能与无效选项的情况区分开。

  1. 清单4:#include <stdio.h>
  2. #include <unistd.h>
  3. int main (int argc, char **argv)
  4. {
  5. int oc; /*选项字符 */
  6. char ec; /*无效的选项字符*/
  7. char *b_opt_arg; /*选项参数字串 */
  8. while((oc = getopt(argc, argv, ":ngl:")) != -1)
  9. {
  10. switch(oc)
  11. {
  12. case 'n':
  13. printf("My name is Lyong./n");
  14. break;
  15. case 'g':
  16. printf("Her name is Xxiong./n");
  17. break;
  18. case 'l':
  19. b_opt_arg = optarg;
  20. printf("Our love is %s/n", optarg);
  21. break;
  22. case '?':
  23. ec = (char)optopt;
  24. printf("无效的选项字符 /' %c /'!/n", ec);
  25. break;
  26. case ':':
  27. printf("缺少选项参数!/n");
  28. break;
  29. }
  30. }
  31. return 0;
  32. }
  33. 测试结果:$ ./opt_parse_demo -a
  34. 无效的选项字符 ' a '!
  35. $ ./opt_parse_demo -l
  36. 缺少选项参数!

7、GNU提供的getopt()函数的特点

上 面所设计的getopt()函数是UNIX支持小组提供的,其执行时一碰到不以'-'开始的命令行参数就停止寻找选项。而GNU提供的getopt()函 数与之不同,它会扫描整个命令行来寻找选项。当调用GNU getopt()函数并处理命令行参数的时候,它重新排列argv中的元素,这样当重排结束时,所有选项都被移动到前面并且那些继续检查argv [optind]至argv[argc-1]中剩余参数的代码仍正常工作,但在任何情况下,碰到特殊参数'--'就结束对选项的扫描。

可以输入一个乱序的命令行,查看opt_parse_demo的输出:

  1. $ ./opt_parse_demo -l forever a b c d -g -n
  2. Our love is forever
  3. Her name is Xxiong.
  4. My name is Lyong.

GNU getopt()第二个特点是可以在optstring中使用特殊的首字符改变getopt()的默认行为:

optstring[0] = '+',这样就与UNIX支持小组提供的getopt()很相近了。

optstring[0] = '-',会在optarg中得到命令行中的每个参数。

以上两种情况下,':'可以作为第二个字符使用。

GNU getopt()第三个特点是optstring中的选项字符后面接两个冒号,就允许该选项有可选的选项参数。在选项参数不存在的情况下,GNU getopt()返回选项字符并将optarg设置为NULL。
8、GNU长选项命令行解析

20 世纪 90 年代,UNIX 应用程序开始支持长选项,即一对短横线、一个描述性选项名称,还可以包含一个使用等号连接到选项的参数。

GNU提供了getopt-long()和getopt-long-only()函数支持长选项的命令行解析,其中,后者的长选项字串是以一个短横线开始的,而非一对短横线。

getopt_long() 是同时支持长选项和短选项的 getopt() 版本。下面是它们的声明:

  1. #include <getopt.h>
  2. int getopt_long(
  3.                            int argc, char * const argv[], 
  4.                            const char *optstring, 
  5.                            const struct option *longopts, 
  6.                             int *longindex
  7.                            );
  8. int getopt_long_only(
  9.                                     int argc, char * const argv[],
  10.                                     const char *optstring,
  11.                                     const struct option *longopts, 
  12.                                     int *longindex
  13.                                      );

getopt_long ()的前三个参数与上面的getopt()相同,第4个参数是指向option结构的数组,option结构被称为“长选项表”。longindex参数 如果没有设置为NULL,那么它就指向一个变量,这个变量会被赋值为寻找到的长选项在longopts中的索引值,这可以用于错误诊断。

option结构在getopt.h中的声明如下:

  1. struct option{
  2.                        const char *name;
  3.                        int has_arg;
  4.                        int *flag;
  5.                        int val;
  6.                        };

对结构中的各元素解释如下:

const char *name----这是选项名,前面没有短横线。譬如"help"、"verbose"之类。

int has_arg ----------描述了选项是否有选项参数。如果有,是哪种类型的参数,此时,它的值一定是下表中的一个。符号常量数值含义 .

no_argument 0-------选项没有参数

required_argument 1 --选项需要参数

optional_argument 2 -- 选项参数可选

int *flag  --------------如果这个指针为NULL,那么getopt_long()返回该结构val字段中的数值。如果该指针不为NULL,getopt_long()会使得它所指 向的变量中填入val字段中的数值,并且getopt_long()返回0。如果flag不是NULL,但未发现长选项,那么它所指向的变量的数值不变。

int val -----------------这 个值是发现了长选项时的返回值,或者flag不是NULL时载入*flag中的值。典型情况下,若flag不是NULL,那么val是个真/假值,譬如1 或0;另一方面,如果flag是NULL,那么val通常是字符常量,若长选项与短选项一致,那么该字符常量应该与optstring中出现的这个选项的 参数相同。

每个长选项在长选项表中都有一个单独条目,该条目里需要填入正确的数值。数组中最后的元素的值应该全是0。数组不需要排序,getopt_long()会进行线性搜索。但是,根据长名字来排序会使程序员读起来更容易。

大部分时候,程序员会根据getopt_long()发现的选项,在选项处理过程中要设置一些标记变量,譬如在使用getopt()时,经常做出如下的程序格式:int do_name, do_gf_name, do_love; /*标记变量*/

  1. char *b_opt_arg;
  2. while((c = getopt(argc, argv, ":ngl:")) != -1)
  3. {
  4. switch (c){
  5. case 'n':
  6. do_name = 1;
  7. case 'g':
  8. do_gf_name = 1;
  9. break;
  10. break;
  11. case 'l':
  12. b_opt_arg = optarg;
  13. ……
  14. }
  15. }

当flag 不为NULL时,getopt_long*()会为你设置标记变量。也就是说上面的代码中,关于选项'n'、'l'的处理,只是设置一些标记,如果 flag不为NULL,时,getopt_long()可以自动为各选项所对应的标记变量设置标记,这样就能够将上面的switch语句中的两种种情况减 少到了一种。下面给出一个长选项表以及相应处理代码的例子。

  1. #include <stdio.h>
  2. #include <getopt.h>
  3. int do_name, do_gf_name;
  4. char *l_opt_arg;
  5. struct option longopts[] = {
  6. "name", no_argument, &do_name, 1 },
  7. "gf_name", no_argument, &do_gf_name, 1 },
  8. "love", required_argument, NULL, 'l' },
  9. { 0, 0, 0, 0},
  10. };
  11. int main(int argc, char *argv[])
  12. {
  13. int c;
  14. while((c = getopt_long(argc, argv, ":l:", longopts, NULL)) != -1){
  15. switch (c){
  16. case 'l':
  17. l_opt_arg = optarg;
  18. printf("Our love is %s!/n", l_opt_arg);
  19. break;
  20. case 0:
  21. printf("getopt_long()设置变量 : do_name = %d/n", do_name);
  22. printf("getopt_long()设置变量 : do_gf_name = %d/n", do_gf_name);
  23. break;
  24. }
  25. }
  26. return 0;
  27. }
  28. 下面测试一下:$ ./long_opt_demo --name
  29. getopt_long()设置变量 : do_name = 1
  30. getopt_long()设置变量 : do_gf_name = 0
  31. $ ./long_opt_demo --gf_name
  32. getopt_long()设置变量 : do_name = 0
  33. getopt_long()设置变量 : do_gf_name = 1
  34. $ ./long_opt_demo --love forever
  35. Our love is forever!
  36. $ ./long_opt_demo -l forever
  37. Our love is forever!

测试过后,应该有所感触了。关于flag和val的讨论到此为止。下面总结一下get_long()的各种返回值的含义:

0 getopt_long()设置一个标志,它的值与option结构中的val字段的值一样

1 每碰到一个命令行参数,optarg都会记录它

'?' 无效选项

':' 缺少选项参数

'x' 选项字符'x'

-1 选项解析结束

从实用的角度来说,我们更期望每个长选项都对应一个短选项,这种情况下,在option结构中,只要将flag设置为NULL,并将val设置为长选项所对应的短选项字符即可。

  1. :#include <stdio.h>
  2. #include <getopt.h>
  3. int do_name, do_gf_name;
  4. char *l_opt_arg;
  5. struct option longopts[] = {
  6. "name", no_argument, NULL, 'n' },
  7. "gf_name", no_argument, NULL, 'g' },
  8. "love", required_argument, NULL, 'l' },
  9. { 0, 0, 0, 0},
  10. };
  11. int main(int argc, char *argv[])
  12. {
  13. int c;
  14. while((c = getopt_long(argc, argv, ":l:", longopts, NULL)) != -1){
  15. switch (c){
  16. case 'n':
  17. printf("My name is LYR./n");
  18. break;
  19. case 'g':
  20. printf("Her name is BX./n");
  21. break;
  22. case 'l':
  23. l_opt_arg = optarg;
  24. printf("Our love is %s!/n", l_opt_arg);
  25. break;
  26. }
  27. }
  28. return 0;
  29. }
  30. 测试结果如下:$ ./long_opt_demo --name --gf_name --love forever
  31. My name is LYR.
  32. Her name is BX.
  33. Our love is forever!
  34. $ ./long_opt_demo -ng -l forever
  35. My name is LYR.
  36. Her name is BX.
  37. Our love is forever!

这些信息可以让你很清晰地了解到命令行参数的解析,有时候在编程的过程中,能给你带来很大的方便,当然,只能说在你需要它的时候,在下面一节我将会通过与g_spawn_command_line_async的结合写出一个实例.

~~END~~

 

抱歉!评论已关闭.