程序参数处理-getopt

╮(╯▽╰)╭,把以前用到的东西粘过来,搞CUI用到

1、 POSIX约定

下面是POSIX标准中关于程序名、参数的约定:

  • 程序名不宜少于 2 个字符且不多于 9 个字符;
  • 程序名应只包含小写字母和阿拉伯数字;
  • 选项名应该是单字符活单数字,且以短横‘ - ‘为前綴;
  • 多个不需要选项参数的选项,可以合并。(譬如: foo -a -b -c ---->foo -abc
  • 选项与其参数之间用空白符隔开;
  • 选项参数不可选。
  • 若选项参数有多值,要将其并为一个字串传进来。譬如: myprog -u "arnold,joe,jane" 。这种情况下,需要自己解决这些参数的分离问题。
  • 选项应该在操作数出现之前出现。
  • 特殊参数‘ --' 指明所有参数都结束了,其后任何参数都认为是操作数。
  • 选项如何排列没有什么关系,但对互相排斥的选项,如果一个选项的操作结果覆盖其他选项的操作结果时,最后一个选项起作用;如果选项重复,则顺序处理。
  • 允许操作数的顺序影响程序行为,但需要作文档说明。
  • 读写指定文件的程序应该将单个参数 '-' 作为有意义的标准输入或输出来对待。

 

2、 命令行参数解析函数getopt()

         getopt()函数声明如下:

#include <unistd.h>

 

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

 

extern char *optarg;

extern int optind, opterr, optopt;

         该函数的argcargv参数通常直接从main()的参数直接传递而来。optstring是选项字母组成的字串。如果该字串里的任一字符后面有冒号,那么这个选项就要求有选项参数。

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

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

         char *optarg——当前选项参数字串(如果有)。

         int optind——argv的当前索引值。当getopt()while循环中使用时,循环结束后,剩                     下的字串视为操作数,在argv[optind]argv[argc-1]中可以找到。

         int opterr——这个变量非零时,getopt()函数为“无效选项”和“缺少参数选项,并输                       出其错误信息。

         int optopt——当发现无效选项字符之时,getopt()函数或返回'?'字符,或返回':'字符。并                   optopt包含了所发现的无效选项字符。,当optstring开头没有指定’:’时,无效选项            或缺参数都返回’?’

 

         简单例子,测试带参选项与不带参选项,代码opt.c

#include<stdio.h>

#include<unistd.h>

 

int main(int argc, char **argv){

  char opc; //option char

 

  while((opc=getopt(argc,argv,"abcd:"))>-1){

switch(opc){

  case 'a' : printf("fuck a! optarg:%s optind:%d opterr:%d/n"

            ,optarg,optind,opterr);break;

      case 'b' : printf("fuck b! optarg:%s optind:%d opterr:%d/n"

                  ,optarg,optind,opterr);break;

      case 'c' : printf("fuck c! optarg:%s optind:%d opterr:%d/n"

                  ,optarg,optind,opterr);break;

      case 'd' : printf("fuck d! optarg:%s optind:%d opterr:%d/n"

                  ,optarg,optind,opterr);break;

      case '?' : printf("fuck ?! optarg:%s optind:%d opterr:%d/n"

                  ,optarg,optind,opterr);break;

    }

  }

return;

}

测试结果。注意最后带参选项-d参数缺失时的处理,处理提示可自定义,后面会讲到。

[root@Amanda optest]# ./opt -a

fuck a! optarg:(null) optind:2 opterr:1

[root@Amanda optest]# ./opt -a -b

fuck a! optarg:(null) optind:2 opterr:1

fuck b! optarg:(null) optind:3 opterr:1

[root@Amanda optest]# ./opt -a -b -c

fuck a! optarg:(null) optind:2 opterr:1

fuck b! optarg:(null) optind:3 opterr:1

fuck c! optarg:(null) optind:4 opterr:1

[root@Amanda optest]# ./opt -a -b -c -d ohyeah

fuck a! optarg:(null) optind:2 opterr:1

fuck b! optarg:(null) optind:3 opterr:1

fuck c! optarg:(null) optind:4 opterr:1

fuck d! optarg:ohyeah optind:6 opterr:1

[root@Amanda optest]# ./opt -cb

fuck c! optarg:(null) optind:1 opterr:1

fuck b! optarg:(null) optind:2 opterr:1

[root@Amanda optest]# ./opt -d

./opt: option requires an argument -- d

fuck ?! optarg:(null) optind:2 opterr:1

  当带参选项检查到无参数输入时,getopt()函数会首先提示 ./opt: option requires an argument -- d然后返回字符’?’赋值于opc

如果不希望输出任何错误信息,或更希望输出自定义的错误信息。可以采用以下两种方法来更改getopt()函数的出错信息输出行为。

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

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

“无效选项” —— getopt()返回'?',由于optopt包含了无效选项字符(比如在上例中使用参数 –x等)。

         “缺少选项参数” —— getopt()返回':',由于选项缺参(比如使用命令”./opt –d ”)。

         如果optstring的第一个字符不是冒号,那么无论是无效选项还是缺少参数,getopt()都返回'?'注意:存在一个问题是,假如使用”./opt  -d -x”,这原本是选项-d参数缺失的情况,但getopt()会错误地把-x认为是-d的参数。

 

<!--[if !supportLists]-->3、 <!--[endif]-->对长选项的支持getopt_long()

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

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

#include <getopt.h>

 

int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);

 

int getopt_long_only(int argc, char * const argv[],const char *optstring,const struct option *longopts, int *longindex);

 

struct option{

    const char *name; //选项名,前面无短横线如help version

    int has_arg;//是否有参数;无0、有1、可选2

    int *flag;

    int val;

};

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

         Option结构中flag字段的含义,如果这个指针为NULL,那么 getopt_long()返回该结构val字段中的数值。如果该指针不为NULLgetopt_long()会使得它所指向的变量中填入val字段中的数值,并且getopt_long()返回0。如果flag不是NULL,但未发现长选项,那么它所指向的变量的数值不变;字段val的的含义,这个值是发现了长选项时的返回值,或者flag不是NULL时载入*flag中的值。典型情况下,若flag不是NULL,那么val是个真/假值,譬如10;另一方面,如果flagNULL,那么 val通常是字符常量,若长选项与短选项一致,那么该字符常量应该与optstring中出现的这个选项的参数相同。

         每个长选项在长选项表中都有一个单独条目,该条目里需要填入正确的数值。数组中最后的元素的值应该全是0。数组不需要排序,getopt_long()会进行线性搜索。函数getopt_long()的所有返回值含义如下。

返回值        含 义

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

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

 '?'       无效选项

 ':'       缺少选项参数

 'x'       选项字符'x',在选项中自由设定的

 -1        选项解析结束

测试用例如下

#include<stdio.h>

#include<unistd.h>

#include<getopt.h>

 

int main(int argc, char **argv){

  char opc; //option char

  struct option longopts[]={

    {"help",no_argument,NULL,'h'},

    {"version",no_argument,NULL,'v'},

    {0,0,0,0}

  };

 

  while((opc=getopt_long(argc,argv,"ab:",longopts,NULL))!=-1){

    switch(opc){

      case 'a' : printf("fuck a! optarg:%s optind:%d opterr:%d/n",

                 optarg,optind,opterr);break;

      case 'b' : printf("fuck b! optarg:%s optind:%d opterr:%d/n",

                 optarg,optind,opterr);break; 

      case 'h' : printf("fuck h! optarg:%s optind:%d opterr:%d/n",

                 optarg,optind,opterr);break;

      case 'v' : printf("fuck v! optarg:%s optind:%d opterr:%d/n",

                 optarg,optind,opterr);break;

      case '?' : printf("fuck ?! optarg:%s optind:%d opterr:%d/n",

                 optarg,optind,opterr);break;

      case ':' : printf("fuck :! optarg:%s optind:%d opterr:%d/n",

                 optarg,optind,opterr);break;

    }

  }

 return;

}

 

测试结果如下:

[root@Amanda optest]# ./optlong -a --version

fuck a! optarg:(null) optind:2 opterr:1

fuck v! optarg:(null) optind:3 opterr:1

[root@Amanda optest]# ./optlong --help

fuck h! optarg:(null) optind:2 opterr:1

         flag不为NULL时,getopt_long*()会为你设置标记变量。如果flag不为NULL,时,getopt_long()可以自动为各选项所对应的标记变量设置标记,这样就能够将switch语句中的情况减少。

 

 

 

 

 

你可能感兴趣的:(struct,unix,测试,null,文档,任务)