zoukankan      html  css  js  c++  java
  • C语言命令行解析函数:getopt/getopt_long

    命令行工具下的参数选项有两种,长选项短选项。短选项以-开头,后面跟单个字母;长选项以--开头,后面可跟多个字母。


    一. getopt()

    1.功能:解析命令行短选项参数

    2.函数原型:

    #include <getopt.h>
    int getopt(int argc, char * const argv[], const char *optstring);

    getopt.h中声明的几个外部变量:
    extern char *optarg;
    extern int optind, opterr, optopt;

    optarg:若短选项后有参数,则optarg指向该参数
    optind:扫描选项时,标识下一个选项的索引;扫描结束后,标识第一个非选项参数索引
    opterr:出现不可识别的选项时,getopt将打印错误信息。将opterr设为0,可不打印错误信息。
    optopt:存放不可识别的选项至optopt

    3.参数
    argc:参数的个数(main)
    argv:参数数组(main)
    optstring:短选项字符集合,如 -i -n中的i,n
    若选项后面有参数,则选项字符后加:, 对应的参数值保存在外部变量optarg中
    如optstring 为"i:a",则表示程序支持两个短选项 -i arg和-a, -i后面须有参数值
    当执行./a.out -i filename -a时,optarg指针就指向filename

    4.解析过程
    getopt首先扫描argv[1]到argv[argc-1],并将选项及参数依次放到argv数组的最左边,非选项参数依次放到argv的最后边
    即该函数会改变argv的排列顺序。

    如执行程序为:

         0         1    2    3    4  5    6     7  8   9 
    $ ./mygetopt file1 -i infile -a -o outfile -v -h file2

    扫描过程中,optind是下一个选项的索引(如-i、-a、-o、-v), 非选项参数将跳过,同时optind增1。optind初始值为1。
    当扫描argv[1]时,为非选项参数,跳过,optind=2; 扫描到-i选项时,后面有参数,下一个将要扫描的选项是-a,则optind更改为4;
    扫描到-a选项时,下一个选项是-o,optind=5; 扫描到-o选项时,后面有参数,下一个选项是-v,optind=7; 扫描到-v选项时,下一个
    选项是-h,optind=8; 扫描到-h选项时,扫描完了,optind=9

    扫描结束后,getopt会将argv数组修改成下面的形式(optstring指定为"i:ao:vh"):

         0       1    2    3  4    5     6  7   8     9
    $./mygetopt -i infile -a -o outfile -v -h file1 file2

    同时,optind会指向非选项的第一个参数,如上面,optind将指向file1

    5.返回值

    若getopt找到短选项字符,则返回该选项字符,如此例中的i a o v h.
    若出现不能接受的选项字符或丢失选项参数,则返回?,同时optopt将被设置成相应选项字符;
    则后面没有选项字符,则返回-1

    6.测试程序

    #include <stdio.h>
    #include <getopt.h>
    
    void usage(const char *p)
    {
        printf("Usage: %s [-i infile] [-a] [-o outfile] [-v] [-h] [file]
    ", p);
    }
    
    int main(int argc, char *argv[])
    {
        int ch=0;
        opterr=0; // prevent error information to print for unrecognized options
        while( (ch=getopt(argc, argv, "i:ao:vh") ) != -1 )
        {
            switch(ch)
            {
            case 'i':
                printf("option i: %s
    ", optarg);/*optind:有参数是选项参数的索引(从1开始)*/
                printf("optind=%d
    
    ", optind);
                break;
            case 'a':
                printf("option a :%c
    ", ch);
                printf("optind=%d
    
    ", optind); /*optind:没有参数是选项本身的索引(从1开始)*/
                break;
            case 'o':
                printf("option o: %s
    ", optarg);
                printf("optind=%d
    
    ", optind);
                break;
            case 'v':
                printf("option v: %c
    ", ch);
                printf("optind=%d
    
    ", optind);
                break;
            case 'h':
                usage(argv[0]);
                printf("optind=%d
    
    ", optind);
                break;
            default:
                printf("unrecognized option: %c
    ", optopt);
                usage(argv[0]);
            }
        }
    
        printf("optind = %d
    ", optind);
    
        if ( optind < argc )
        {
            printf("
    non-option arguments below:
    ");
            while( optind < argc )
            {
                printf("%s
    ", argv[optind++]);
            }
        }
    
        for(ch=0; ch<argc; ch++)
        {
            printf("%s ",argv[ch]);
        }
        printf("
    ");
        return 0;
    }
                                   0    1     2    3   4    5   6      7   8    9     10   11     12   13   14      15 
    ubuntu@ubuntu:~/mytest/test$ ./pp file1 file2 -i infile -a baidu sina -o outfile -v renmin google -h bluestar file2 option i: infile optind=5 option a :a optind=6 option o: outfile optind=10 option v: v optind=11 Usage: ./pp [-i infile] [-a] [-o outfile] [-v] [-h] [file] optind=14 /*-h因为它没有参数,所以直接是下一个元素*/ optind = 8 /*第一个非法参数*/ non-option arguments below: file1 file2 baidu sina renmin google bluestar file2

    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 .
    /pp -i infile -a -o outfile -v -h file1 file2 baidu sina renmin google bluestar file2

    注:
    getopt()的返回后,如果有选项参数的话optarg指向选项参数,并且变量optind包含下一个argv参数作为对getopt()下一次调用的索引。
    变量optopt保存最后一个由getopt()返回的已知的选项。
    在调用getopt()之前,将opterr设置为0,这样就可以在getopt()函数发现错误的时候强制它不输出任何消息。

    二、getopt_long()

    1.功能
    支持长选项的命令行解析

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

    3.参数
    argc和argv通常直接从main()的两个参数传递而来
    optsting是选项参数组成的字符串,表示可以接受的参数。例如,"a:b:cd"
    longopts是一个结构体数组,option结构称为长选项表,其声明如下:
    struct option {
      const char *name;
      int has_arg;
      int *flag;
      int val;
    };

    结构中的元素解释如下:
      const char *name :选项名,前面没有短横线。譬如"help"、"verbose"之类。
      int has_arg :描述长选项是否有选项参数,如果有,是哪种类型的参数,其值见下表:
    符号常量 数值 含义
        no_argument 0 选项没有参数
        required_argument 1 选项需要参数
        optional_argument 2 选项参数是可选的
      nt *flag :如果该指针为NULL,那么getopt_long返回val字段的值;如果该指针不为NULL,那么会使得它所指向
    的结构填入val字段的值,同时getopt_long返回0;
      int val :如果flag是NULL,那么val通常是个字符常量,如果短选项和长选项一致,那么该字符就应该与optstring中出现
    的这个选项的参数相同;

      longindex参数一般赋为NULL即可;如果没有设置为NULL,那么它就指向一个变量,这个变量会被赋值为寻找到的长选项在longopts
    中的索引值,这可以用于错误诊断。

    对于options类型参数可以有两种方式:
    1)短选项(short options): 它们通常包含一个连字号和一个字母(大写或小写字母)。例如:-s,-h等。
    2)长选项(long options) : 包含了两个连字号和一些大小写字母组成的单词。例如,--size,--help等。

    4.返回值
    每次调用getopt_long,它会解析一个符号,返回相应的短选项字符,如果解析完毕返回-1
    如果getopt_long遇到一个无效的选项字符,它会打印一个错误消息并且返回'?'
    当getopt_long解析到一个长选项并且发现后面没有参数则返回':',表示缺乏参数。

    当处理一个参数时,全局变量optarg指向下一个要处理的变量。当getopt_long处理完所有的选项后,全局变
    量optind指向第一个未知的选项索引。

    #include <stdio.h>
    #include <getopt.h>
    
    int do_name, do_gf_name;
    char *l_opt_arg;
    static const char *shortopts = "l:ng";
    
    struct option longopts[] = {
      {"name",    no_argument,       NULL, 'n'},
      {"good", no_argument,       NULL, 'g'},
      {"love",    required_argument, NULL, 'l'},
      {0,         0,                 0,      0},
    };
    
    int main (int argc, char *argv[])
    {
        int c;
        while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
        {
            switch (c)
            {
            case 'n':
                printf ("nnnnn.
    ");
                break;
            case 'g':
                printf ("ggggg.
    ");
                break;
            case 'l':
                l_opt_arg = optarg;
                printf ("%s!
    ", l_opt_arg);
                break;
            }
        }
    
        return 0;
    }

    6.结果

    $ ./dd --name
    nnnnn.
    $ ./dd --good
    ggggg.
    $ ./dd --love you
    you!

     

  • 相关阅读:
    Java 7如何操纵文件属性
    MS Server中varchar与nvarchar的区别
    【Unity3D】【NGUI】UICamera
    2007LA 3902 网络(树+贪心)
    读取图片的几种方式
    AssetsLibrary 实现访问相册,选取多张照片显示
    UIImagePickerController的用法
    画板的实现
    最近的状态
    富文本的使用-----实现图文混排 文字的检索 (正则表达式)
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/9102924.html
Copyright © 2011-2022 走看看