• getopt、getopt_long和getopt_long_only解析命令行参数


    一:posix约定:

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

             程序名不宜少于2个字符且不多于9个字符;

             程序名应只包含小写字母和阿拉伯数字;

             选项名应该是单字符或单数字,且以短横 ‘-’ 为前綴;

             多个不需要选项参数的选项,可以合并。(譬如:foo  -a -b -c  ----> foo  -abc)

             选项与其参数之间用空白符隔开;

             选项参数不可选。

             若选项参数有多值,要将其并为一个字串传进来。譬如:myprog -u "arnold,joe,jane"。这种情况下,需要自己解决这些参数的分离问题。

             选项应该在操作数出现之前出现。

             特殊参数 ‘--’ 指明所有参数都结束了,其后任何参数都认为是操作数。

             选项如何排列没有什么关系,但对互相排斥的选项,如果一个选项的操作结果覆盖其他选项的操作结果时,最后一个选项起作用;如果选项重复,则顺序处理。

             允许操作数的顺序影响程序行为,但需要作文档说明。

             读写指定文件的程序应该将单个参数 ‘-’ 作为有意义的标准输入或输出来对待。

     

    二:getopt


    #include <unistd.h>
     
    int getopt(int argc, char *const argv[], const char *optstring);
    extern char *optarg;</span></span>
    extern int opterr, optind, optopt;

    
    

              argc和argv分别是调用main函数时传递的参数。在argv中,以 ‘-’ 开头的元素就是选项。该参数中除了开头的 ‘-’ 以外的字母就是选项字符。如果重复调用getopt函数,则该函数会持续的返回每个选项中的选项字符。            

     

              optstring是包含合法选项字符的字符串。该字符串中,每一个字符都可以是合法的选项字符。

              如果字符后面跟了一个冒号’:’ ,则说明这个选项字符需要一个参数,这个参数要么紧跟在选项字符的后面(同一个命令行参数),要么就是下一个命令行参数。通过指针optarg指向这个参数。

              如果字符后面跟了两个冒号’::’ ,则说明该选项字符后面跟可选参数,而且这个可选参数必须紧跟在选项字符的后面(同一个命令行参数,比如-oarg。如果有参数的话,通过指针optarg指向这个参数,否则,optarg置为NULL。

              在GNU的扩展中,如果optstring字符串中包含“W;”(’W’加上一个分号),则 -W foo会被当做长参数 --foo来处理。

     

              变量optind是搜索选项的索引。初始值为1,每次调用getopt函数,optind就会置为下次要开始搜索的参数索引。

     

              getopt函数返回每次找到的选项字符,如果没有选项了,则返回-1。并且,optind置为指向第一个非选项参数的索引。默认情况下,getopt函数在扫描的过程中会重新排序argv,这样,最终所有非选项参数都会排在argv参数表的后面。

              示例代码如下:

    int main(int argc, char * argv[])
    {
        int aflag=0, bflag=0, cflag=0;
        int i = 0;
        int ch;
        printf("begin: optind:%d,opterr:%d
    ", optind, opterr);
        for(i = 0; i < argc; i++)
        {
            printf("argc[%d]: %s	", i,argv[i]);
        }
        printf("
    --------------------------
    ");
        while ((ch = getopt(argc, argv,"ab::c:de::")) != -1)
        {
            switch (ch)
            {
                case 'a':
                {
                    printf("HAVE option:-a
    ");
                    break;
                }
                case 'b':
                {
                    printf("HAVE option:-b
    ");       
                    printf("The argument of -bis %s
    ", optarg);
                    break;
                }
                case 'c':
                {
                    printf("HAVE option:-c
    ");
                    printf("The argument of -cis %s
    ", optarg);
                    break;
                }
                case 'd':
                {
                    printf("HAVE option:-d
    ");
                    break;
                }
                case 'e':
                {
                    printf("HAVE option:-e
    ");
                    printf("The argument of -eis %s
    ", optarg);
                    break;
                }
                case ':':
                {
                    printf("option %c missingarguments
    ", (char)optopt);
                    break;
                }
                case '?':
                {
                    printf("Unknown option:%c
    ",(char)optopt);
                    break;
                }
                default:
                {
                    printf("the option is%c--->%d, the argu is %s
    ", ch, ch, optarg);
                    break;
                }
            }
            printf("optind: %d
    
    ",optind);
        }
        printf("----------------------------
    ");
        printf("end:optind=%d,argv[%d]=%s
    ",optind,optind,argv[optind]);
        for(i = 0; i < argc; i++)
        {
            printf("argc[%d]: %s	", i,argv[i]);
        }
        printf("
    ");
    }

              上面的程序,optstring为“ab::c:de::”,说明选项a,d不需要参数,选项c必须有参数,选项b,e有可选参数。如果输入:

    ./1  -a  f1  -b  f2  -c  f3  -d  f4  -e  f5

              则输出:

    begin: optind:1,opterr:1

    argc[0]: ./1    argc[1]:-a     argc[2]: f1     argc[3]: -b     argc[4]: f2     argc[5]: -c     argc[6]: f3     argc[7]: -d      argc[8]: f4     argc[9]: -e     argc[10]: f5

    --------------------------

    HAVE option: -a

    optind: 2

     

    HAVE option: -b

    The argument of -b is (null)

    optind: 4

     

    HAVE option: -c

    The argument of -c is f3

    optind: 7

     

    HAVE option: -d

    optind: 8

     

    HAVE option: -e

    The argument of -e is (null)

    optind: 10

     

    ----------------------------

    end:optind=7, argv[7]=f1

    argc[0]: ./1    argc[1]:-a     argc[2]: -b     argc[3]: -c     argc[4]: f3     argc[5]: -d     argc[6]: -e     argc[7]: f1      argc[8]: f2     argc[9]: f4     argc[10]: f5

     

              如果optstring的第一个字符是’+’(或者设置了环境变量POSIXLY_CORRECT),则在扫描命令行参数的过程中,一旦碰到非选项参数就会停止。

              比如上面的程序,如果optstring为” +ab::c:de::”,如果输入:

    ./1  -a  f1  -b  f2  -c  f3  -d  f4  -e  f5

    输出:

    begin: optind:1,opterr:1

    argc[0]: ./1    argc[1]:-a     argc[2]: f1     argc[3]: -b     argc[4]: f2     argc[5]: -c     argc[6]: f3     argc[7]: -d      argc[8]: f4     argc[9]: -e     argc[10]: f5

    --------------------------

    HAVE option: -a

    optind: 2

     

    ----------------------------

    end: optind=2, argv[2]=f1

    argc[0]: ./1    argc[1]:-a     argc[2]: f1     argc[3]: -b     argc[4]: f2     argc[5]: -c     argc[6]: f3     argc[7]: -d      argc[8]: f4     argc[9]: -e     argc[10]: f5

     

              如果optstring的第一个字符是’-’,则所有的非选项参数都会被当做数字1的选项的参数。         比如上面的程序,如果optstring为” -ab::c:de::”,如果输入:

    ./1  -a  f1  -b  f2  -c  f3  -d  f4  -e  f5

    输出:

    begin: optind:1,opterr:1

    argc[0]: ./1    argc[1]:-a     argc[2]: f1     argc[3]: -b     argc[4]: f2     argc[5]: -c     argc[6]: f3     argc[7]: -d      argc[8]: f4     argc[9]: -e     argc[10]: f5

    --------------------------

    HAVE option: -a

    optind: 2

     

    the option is --->1, the argu is f1

    optind: 3

     

    HAVE option: -b

    The argument of -b is (null)

    optind: 4

     

    the option is --->1, the argu is f2

    optind: 5

     

    HAVE option: -c

    The argument of -c is f3

    optind: 7

     

    HAVE option: -d

    optind: 8

     

    the option is --->1, the argu is f4

    optind: 9

     

    HAVE option: -e

    The argument of -e is (null)

    optind: 10

     

    the option is --->1, the argu is f5

    optind: 11

     

    ----------------------------

    end: optind=11,argv[11]=(null)

    argc[0]: ./1   argc[1]: -a     argc[2]: f1     argc[3]: -b     argc[4]: f2     argc[5]: -c     argc[6]: f3     argc[7]: -d      argc[8]: f4     argc[9]: -e     argc[10]: f5

     

              如果在命令行参数中有’--’,不管optstring是什么,扫描都会停止。

              比如上面的程序,如果optstring为” ab::c:de::”如果输入:

    ./getopt  -a  f1  -b  f2  --  -c  f3  -d  f4  -e  f5

    输出:

    begin: optind:1,opterr:1

    argc[0]: ./1    argc[1]:-a     argc[2]: f1     argc[3]: -b     argc[4]: f2     argc[5]: --     argc[6]: -c     argc[7]: f3      argc[8]: -d     argc[9]: f4     argc[10]: -e    argc[11]: f5

    --------------------------

    HAVE option: -a

    optind: 2

     

    HAVE option: -b

    The argument of -b is (null)

    optind: 4

     

    ----------------------------

    end: optind=4,argv[4]=f1

    argc[0]: ./1    argc[1]:-a     argc[2]: -b     argc[3]: --     argc[4]: f1     argc[5]: f2     argc[6]: -c     argc[7]: f3      argc[8]: -d     argc[9]: f4     argc[10]: -e    argc[11]: f5

             

              如果命令行参数中,有optstring中没有的字符,则将会打印错误信息,并且将这个字符存储到optopt中,返回 ’?’。如果不想打印错误信息,则可以设置变量opterr为0.

              比如上面的程序,如果optstring为"ab::c:de::”,

    如果输入:./getopt -a  f1  -b  f2  -t  -c  f3

    则输出:

    begin: optind:1,opterr:1

    argc[0]: ./1    argc[1]:-a     argc[2]: f1     argc[3]: -b     argc[4]: f2     argc[5]: -t     argc[6]: -c     argc[7]: f3

    --------------------------

    HAVE option: -a

    optind: 2

     

    HAVE option: -b

    The argument of -b is (null)

    optind: 4

     

    ./1: invalid option -- t

    Unknown option: t

    optind: 6

     

    HAVE option: -c

    The argument of -c is f3

    optind: 8

     

    ----------------------------

    end: optind=6,argv[6]=f1

    argc[0]: ./1   argc[1]: -a     argc[2]: -b     argc[3]: -t     argc[4]: -c     argc[5]: f3     argc[6]: f1     argc[7]: f2

     

              如果某个选项字符后应该跟参数,但是命令行参数中没有,则根据optstring中的首字符的不同返回不同的值,如果optstring首字符不是’:’ ,则返回 ’?’ ,打印错误信息,并且设置optopt为该选项字符。如果optstring首字符是’:’ (或者首字符是’+’ 、’-’ ,且第二个字符是’:’ ),则返回’:’ ,并且设置optopt为该选项字符,但是不在打印错误信息。

              比如上面的程序,如果optstring为“ab::c:de::”,如果输入:

    ./getopt  -a  f1  -b  f2  -c

    则输出:

    begin: optind:1,opterr:1

    argc[0]: ./1    argc[1]:-a     argc[2]: f1     argc[3]: -b     argc[4]: f2     argc[5]: -c

    --------------------------

    HAVE option: -a

    optind: 2

     

    HAVE option: -b

    The argument of -b is (null)

    optind: 4

     

    ./1: option requires an argument -- c

    Unknown option: c

    optind: 6

     

    ----------------------------

    end: optind=4,argv[4]=f1

    argc[0]: ./1    argc[1]:-a     argc[2]: -b     argc[3]: -c     argc[4]: f1     argc[5]: f2

     

              如果optstring为“:ab::c:de::”,如果输入:

    ./getopt  -a  f1  -b  f2  -c

    则输出:

    begin: optind:1,opterr:1

    argc[0]: ./1    argc[1]:-a     argc[2]: f1     argc[3]: -b     argc[4]: f2     argc[5]: -c

    --------------------------

    HAVE option: -a

    optind: 2

     

    HAVE option: -b

    The argument of -b is (null)

    optind: 4

     

    option c missing arguments

    optind: 6

     

    ----------------------------

    end: optind=4,argv[4]=f1

    argc[0]: ./1    argc[1]:-a     argc[2]: -b     argc[3]: -c     argc[4]: f1     argc[5]: f2

     

     

    三:getopt_long和 getopt_long_only

    #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);

              getopt不能处理长选项,也就是’-- ‘开头的选项,处理长选项需要用getopt_long或者getopt_long_only.

              getopt_long具有getopt函数的功能,而且还可以处理’--’开头的长选项,一般来说,长选项都有对应的短选项。optstring的意义仅限于短选项,这与getopt中是一致的。如果仅需要该函数处理长选项,则可以将optstring置为空字符串””(不是NULL)。

              长选项也可以带参数,比如:--arg=param或 --arg param。

             

              函数参数longopts指向一个数组,该数组元素为structoption,如下:

               struct option {

                   const char*name;

                   int         has_arg;

                   int        *flag;

                   int         val;

               };

              其中:

              name是长参数的名字。

              has_arg指明了该长参数是否需要参数,有三种取值,no_argument (or 0)表明不需要参数,required_argument (or 1)表明需要参数,optional_argument(or 2)表明有可选参数。

              flag指明了函数返回值,如果flag为NULL,则函数返回val(一般将val设置为长参数对应的短参数)。如果flag不是NULL,则返回0,而且如果相应的长参数找到了,则flag指向的整数被置为val。

              该数组的最后一个元素的结构体,成员都要设置为0。


              如果longindex不是NULL, 则长参数找到时,它指向的整数被置为相应的longopts数组索引。

              上面的getopt程序,如果换成相应的getopt_long调用的话,函数依然工作正常,而且返回打印与getopt一样。说明getopt_long既可以处理短选项,也能处理长选项。

              例子如下:

     

    #include <unistd.h>
    #include <stdio.h>
    #include <getopt.h>
    int main(int argc, char * argv[])
    {
        int aflag=0, bflag=0,cflag=0;
        int i = 0;
        int ch;
        int optionindex = -1;
        struct option long_options[] ={
                   {"add",     required_argument, NULL,  'a' },
                   {"delete",  required_argument, NULL,  'd' },
                   {"verbose",no_argument,       NULL,  'v' },
                   {"create",  required_argument, NULL,  'c'},
                   {"file",    required_argument, NULL,  'f' },
                   {0,         0,                 0,  0 }
               };
     
        printf("begin: optind:%d,opterr:%d
    ",optind,opterr);
        for(i = 0; i <argc; i++)
        {
            printf("argc[%d]:%s	", i, argv[i]);
        }
        printf("
    --------------------------
    ");
        while ((ch =getopt_long(argc, argv, "a:d:vc:f:",long_options, &optionindex)) != -1)
        {
           
            printf("return value is %c
    ", ch);
            printf("optionindex is %d
    ", optionindex);
            if(optarg)
            {
                printf("%c option arguis %s
    ", ch, optarg);
            }
            if(optionindex != -1)
            {
                printf("long arg nameis %s
    ", long_options[optionindex].name);
            }
            printf("optind:%d
    
    ", optind);
        }
        printf("----------------------------
    ");
        printf("end:optind=%d,argv[%d]=%s
    ",optind,optind,argv[optind]);
        for(i = 0; i <argc; i++)
        {
            printf("argc[%d]:%s	", i, argv[i]);
        }
        printf("
    ");
    }

    如果输入:

    ./1  --add

    输出:

    begin: optind:1,opterr:1

    argc[0]: ./ getoptlong                                     argc[1]: --add            

    --------------------------

    ./1: option '--add' requires an argument

    return value is ?

    optionindex is -1

    optind: 2

     

    ----------------------------

    end: optind=2,argv[2]=(null)

    argc[0]: ./1                  argc[1]:--add            

     

    如果输入:

    ./1  --add=a1 f0  --file  f1  -a  a2  -f  f2

    begin: optind:1,opterr:1

    argc[0]: ./1                  argc[1]:--add=a1      argc[2]: f0                                      argc[3]: --file              argc[4]:f1      argc[5]: -a         argc[6]: a2                                     argc[7]: -f                    argc[8]:f2                  

    --------------------------

    return value is a

    optionindex is 0

    a option argu is a1

    long arg name is add

    optind: 2

     

    return value is f

    optionindex is 4

    f option argu is f1

    long arg name is file

    optind: 5

     

    return value is a

    optionindex is 4

    a option argu is a2

    long arg name is file

    optind: 7

     

    return value is f

    optionindex is 4

    f option argu is f2

    long arg name is file

    optind: 9

     

    ----------------------------

    end: optind=8,argv[8]=f0

    argc[0]: ./1                  argc[1]:--add=a1      argc[2]: --file              argc[3]: f1                                      argc[4]:-a      argc[5]: a2        argc[6]: -f                    argc[7]: f2                                      argc[8]: f0

     

              可见,在处理既有短选项,又有长选项的情况下,最好每次都把optionindex置为无效值,比如-1,这样就可以区分长短选项了。

     

              如果输入:./1  --add  a1 --cao  f0  --file  f1 -a  a2  -f  f2

    begin: optind:1,opterr:1

    argc[0]: ./1                  argc[1]:--add             argc[2]: a1                                     argc[3]: --cao             argc[4]:f0      argc[5]: --file    argc[6]: f1                                      argc[7]: -a                                      argc[8]: a2                        argc[9]: -f          argc[10]: f2                

    --------------------------

    return value is a

    optionindex is 0

    a option argu is a1

    long arg name is add

    optind: 3

     

    ./1: unrecognized option '--cao'

    return value is ?

    optionindex is 0

    long arg name is add

    optind: 4

     

    return value is f

    optionindex is 4

    f option argu is f1

    long arg name is file

    optind: 7

     

    return value is a

    optionindex is 4

    a option argu is a2

    long arg name is file

    optind: 9

     

    return value is f

    optionindex is 4

    f option argu is f2

    long arg name is file

    optind: 11

     

    ----------------------------

    end: optind=10,argv[10]=f0

    argc[0]: ./1                  argc[1]:--add             argc[2]: a1                                     argc[3]: --cao             argc[4]:--file                              argc[5]:f1                                      argc[6]: -a                                      argc[7]: a2                        argc[8]: -f          argc[9]: f2                   argc[10]:f0                

     

              getopt_long_only函数与getopt_long函数类似,只不过把’-’后的选项依然当做长选项,如果一个以’-’开头的选项没有在option数组中找到匹配的选项,但是在optstring中有匹配的短选项,则当成短选项处理。


    四:实例

              下面的例子来自于开源软件WebBench,一个网站压力测试工具,代码如下:

    /* globals */
    int http10=1; 		/* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */
    #define METHOD_GET 0
    #define METHOD_HEAD 1
    #define METHOD_OPTIONS 2
    #define METHOD_TRACE 3
    #define PROGRAM_VERSION "1.5"
    
    int method=METHOD_GET;
    int clients=1;
    int force=0;
    int force_reload=0;
    int proxyport=80;
    char *proxyhost=NULL;
    int benchtime=30;
    
    static const struct option long_options[]=
    {
     {"force",no_argument,&force,1},
     {"reload",no_argument,&force_reload,1},
     {"time",required_argument,NULL,'t'},
     {"help",no_argument,NULL,'?'},
     {"http09",no_argument,NULL,'9'},
     {"http10",no_argument,NULL,'1'},
     {"http11",no_argument,NULL,'2'},
     {"get",no_argument,&method,METHOD_GET},
     {"head",no_argument,&method,METHOD_HEAD},
     {"options",no_argument,&method,METHOD_OPTIONS},
     {"trace",no_argument,&method,METHOD_TRACE},
     {"version",no_argument,NULL,'V'},
     {"proxy",required_argument,NULL,'p'},
     {"clients",required_argument,NULL,'c'},
     {NULL,0,NULL,0}
    };
    
    static void usage(void)
    {
       fprintf(stderr,
        "webbench [option]... URL
    "
        "  -f|--force               Don't wait for reply from server.
    "
        "  -r|--reload              Send reload request - Pragma: no-cache.
    "
        "  -t|--time <sec>          Run benchmark for <sec> seconds. Default 30.
    "</span>
        "  -p|--proxy <server:port> Use proxy server for request.
    "
        "  -c|--clients <n>         Run <n> HTTP clients at once. Default one.
    "
        "  -9|--http09              Use HTTP/0.9 style requests.
    "
        "  -1|--http10              Use HTTP/1.0 protocol.
    "
        "  -2|--http11              Use HTTP/1.1 protocol.
    "
        "  --get                    Use GET request method.
    "
        "  --head                   Use HEAD request method.
    "
        "  --options                Use OPTIONS request method.
    "
        "  --trace                  Use TRACE request method.
    "
        "  -?|-h|--help             This information.
    "
        "  -V|--version             Display program version.
    "
        );
    };
    
    void printval()
    {
        printf("force is %d
    ", force);
        printf("force_reload is %d
    ", force_reload);
        printf("benchtime is %d
    ", benchtime);
        printf("proxyhost:proxyport is %s:%d
    ", proxyhost, proxyport);
        printf("clients is %d
    ", clients);
        printf("http10 is %d
    ", http10);
        printf("method is %d
    ", method);
    }
    
    
    int main(int argc, char *argv[])
    {
        int opt=0;
        int options_index=0;
        char *tmp=NULL;
    
        if(argc==1)
        {
            usage();
            return 2;
        } 
    
        while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options, &options_index))!=EOF)
        {
            printf("opt is %d(%c)
    ", opt, opt);
            switch(opt)
            {
                case  0 : break;
                case 'f': force=1;break;
                case 'r': force_reload=1;break; 
                case '9': http10=0;break;
                case '1': http10=1;break;
                case '2': http10=2;break;
                case 'V': printf(PROGRAM_VERSION"
    ");exit(0);
                case 't': benchtime=atoi(optarg);break;      
                case 'p': 
                     /* proxy server parsing server:port */
                     tmp=strrchr(optarg,':');
                     proxyhost=optarg;
                     if(tmp==NULL)
                     {
                         break;
                     }
                     if(tmp==optarg)
                     {
                         fprintf(stderr,"Error in option --proxy %s: Missing hostname.
    ",optarg);
                         return 2;
                     }
                     if(tmp==optarg+strlen(optarg)-1)
                     {
                         fprintf(stderr,"Error in option --proxy %s Port number is missing.
    ",optarg);
                         return 2;
                     }
                     *tmp='';
                     proxyport=atoi(tmp+1);break;
                case ':':
                case 'h':
                case '?': usage();return 2;break;
                case 'c': clients=atoi(optarg);break;
            }
        }
    
        if(optind==argc) 
        {
            fprintf(stderr,"webbench: Missing URL!
    ");
            usage();
            return 2;
        }
    
        printval();
        printf("argv[optind] is %s
    ", argv[optind]);
    }
    


  • 相关阅读:
    实现类似add(1)(2)(3)的函数
    Chrome安装助手踩坑
    升级webpack4错误处理
    vue项目埋点
    如何理解vue中的v-bind?
    不能不知道的webpack基本配置
    IE9及以下浏览器升级提示
    HTML5常用API
    css中clip属性
    Web开发展望
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247141.html
Copyright © 2020-2023  润新知