zoukankan      html  css  js  c++  java
  • linux的命令行解析参数之getopt_long函数

    前言

    在linux中,经常需要各种命令,通常情况下都会带各种参数,而这些参数是如何解析的呢?通常使用GNU C提供的函数getopt、getopt_long、getopt_long_only函数来解析命令行参数。

    一、关于命令行参数

    命令行参数可以分为两类,一类是短选项,一类是长选项,短选项在参数前加一杠"-",长选项在参数前连续加两杠"--",如下表(ls 命令参数)所示,其中-a,-A,-b都表示短选项,--all,--almost-all, --author都表示长选项。他们两者后面都可选择性添加额外参数。比如--block-size=SIZE,SIZE便是额外的参数。

    二、getopt_long函数

    getopt函数只能处理短选项,而getopt_long函数两者都可以,可以说getopt_long已经包含了getopt_long的功能。因此,这里就只介绍getopt_long函数。而getopt_long与getopt_long_only的区别很小,等介绍完getopt_long,在提起会更好。

    #include <unistd.h>  
    extern char *optarg;  
    extern int optind, opterr, optopt;  
    #include <getopt.h>
    int getopt(int argc, char * const argv[],const char *optstring);  
    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);
    

    参数以及返回值介绍(以上三个函数都适用):

    1、argc和argv和main函数的两个参数一致。

    2、optstring: 表示短选项字符串。

    形式如“a:b::cd:“,分别表示程序支持的命令行短选项有-a、-b、-c、-d,冒号含义如下:
    (1)只有一个字符,不带冒号——只表示选项, 如-c 
    (2)一个字符,后接一个冒号——表示选项后面带一个参数,如-a 100
    (3)一个字符,后接两个冒号——表示选项后面带一个可选参数,即参数可有可无, 如果带参数,则选项与参数直接不能有空格
        形式应该如-b200
    

    3、longopts:表示长选项结构体。结构如下:

    struct option 
    {  
         const char *name;  
         int         has_arg;  
         int        *flag;  
         int         val;  
    };  
    

    eg:

     static struct option longOpts[] = {
          { "daemon", no_argument, NULL, 'D' },
          { "dir", required_argument, NULL, 'd' },
          { "out", required_argument, NULL, 'o' },
          { "log", required_argument, NULL, 'l' },
          { "split", required_argument, NULL, 's' },
          { "http-proxy", required_argument, &lopt, 1 },
          { "http-user", required_argument, &lopt, 2 },
          { "http-passwd", required_argument, &lopt, 3 },
          { "http-proxy-user", required_argument, &lopt, 4 },
          { "http-proxy-passwd", required_argument, &lopt, 5 },
          { "http-auth-scheme", required_argument, &lopt, 6 },
          { "version", no_argument, NULL, 'v' },
          { "help", no_argument, NULL, 'h' },
          { 0, 0, 0, 0 }
        };
    

    (1) name:表示选项的名称,比如daemon,dir,out等。

    (2) has_arg:表示选项后面是否携带参数。该参数有三个不同值,如下:

           a:  no_argument(或者是0)时   ——参数后面不跟参数值,eg: --version,--help
           b: required_argument(或者是1)时 ——参数输入格式为:--参数 值 或者 --参数=值。eg:--dir=/home
           c: optional_argument(或者是2)时  ——参数输入格式只能为:--参数=值  
    

    (3) flag:这个参数有两个意思,空或者非空。

           a:如果参数为空NULL,那么当选中某个长选项的时候,getopt_long将返回val值。
                   eg,可执行程序 --help,getopt_long的返回值为h.             
    
           b:如果参数不为空,那么当选中某个长选项的时候,getopt_long将返回0,并且将flag指针参数指向val值。
                   eg: 可执行程序 --http-proxy=127.0.0.1:80 那么getopt_long返回值为0,并且lopt值为1。
    

    (4) val:表示指定函数找到该选项时的返回值,或者当flag非空时指定flag指向的数据的值val。

    4、longindex:longindex非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值。

    5、全局变量:

        (1)optarg:表示当前选项对应的参数值。
    
        (2)optind:表示的是下一个将被处理到的参数在argv中的下标值。
    
        (3)opterr:如果opterr = 0,在getopt、getopt_long、getopt_long_only遇到错误将不会输出错误信息到标准输出流。opterr在非0时,向屏幕输出错误。
    
        (4)optopt:表示没有被未标识的选项。
    

    6、返回值:

         (1)如果短选项找到,那么将返回短选项对应的字符。
    
         (2)如果长选项找到,如果flag为NULL,返回val。如果flag不为空,返回0
    
         (3)如果遇到一个选项没有在短字符、长字符里面。或者在长字符里面存在二义性的,返回“?”
    
         (4)如果解析完所有字符没有找到(一般是输入命令参数格式错误,eg: 连斜杠都没有加的选项),返回“-1”
    
         (5)如果选项需要参数,忘了添加参数。返回值取决于optstring,如果其第一个字符是“:”,则返回“:”,否则返回“?”。
    

    注意:

        (1)longopts的最后一个元素必须是全0填充,否则会报段错误
    
        (2)短选项中每个选项都是唯一的。而长选项如果简写,也需要保持唯一性。
    

    三、测试(自行测试)

    1、官网给出测试用例。

    #include <stdio.h>     /* for printf */
    #include <stdlib.h>    /* for exit */
    #include <getopt.h>
     
    int
    main(int argc, char **argv)
    {
        int c;
        int digit_optind = 0;
     
       while (1) {
            int this_option_optind = optind ? optind : 1;
            int option_index = 0;
            static struct option long_options[] = {
                {"add",     required_argument, 0,  0 },
                {"append",  no_argument,       0,  0 },
                {"delete",  required_argument, 0,  0 },
                {"verbose", no_argument,       0,  0 },
                {"create",  required_argument, 0, 'c'},
                {"file",    required_argument, 0,  0 },
                {0,         0,                 0,  0 }
            };
     
           c = getopt_long(argc, argv, "abc:d:012",
                     long_options, &option_index);
            if (c == -1)
                break;
     
           switch (c) {
            case 0:
                printf("option %s", long_options[option_index].name);
                if (optarg)
                    printf(" with arg %s", optarg);
                printf("\n");
                break;
     
           case '0':
            case '1':
            case '2':
                if (digit_optind != 0 && digit_optind != this_option_optind)
                  printf("digits occur in two different argv-elements.\n");
                digit_optind = this_option_optind;
                printf("option %c\n", c);
                break;
     
           case 'a':
                printf("option a\n");
                break;
     
           case 'b':
                printf("option b\n");
                break;
     
           case 'c':
                printf("option c with value '%s'\n", optarg);
                break;
     
           case 'd':
                printf("option d with value '%s'\n", optarg);
                break;
     
           case '?':
                break;
     
           default:
                printf("?? getopt returned character code 0%o ??\n", c);
            }
        }
     
       if (optind < argc) {
            printf("non-option ARGV-elements: ");
            while (optind < argc)
                printf("%s ", argv[optind++]);
            printf("\n");
        }
     
       exit(EXIT_SUCCESS);
    }
    

    2、自己项目相关一个例子。

    #include<stdio.h>
    #include <getopt.h>
    #include<iostream>
    #include<string>
    #include<stdlib.h>
    using namespace std;
     
    void showUsage() {
      //cout << "Usage: " << PACKAGE_NAME << " [options] URL ..." << endl;
      cout << "Options:" << endl;
      cout << " -d, --dir=DIR              The directory to store downloaded file." << endl;
      cout << " -o, --out=FILE             The file name for downloaded file." << endl;
      cout << " -l, --log=LOG              The file path to store log. If '-' is specified," << endl;
      cout << "                            log is written to stdout." << endl;
      cout << " -D, --daemon               Run as daemon." << endl;
      cout << " -s, --split=N              Download a file using s connections. s must be" << endl;
      cout << "                            between 1 and 5. If this option is specified the" << endl;
      cout << "                            first URL is used, and the other URLs are ignored." << endl;
      cout << " --http-proxy=HOST:PORT     Use HTTP proxy server. This affects to all" << endl;
      cout << "                            URLs." << endl;
      cout << " --http-user=USER           Set HTTP user. This affects to all URLs." << endl;
      cout << " --http-passwd=PASSWD       Set HTTP password. This affects to all URLs." << endl;
      cout << " --http-proxy-user=USER     Set HTTP proxy user. This affects to all URLs" << endl;
      cout << " --http-proxy-passwd=PASSWD Set HTTP proxy password. This affects to all URLs." << endl;
      cout << " --http-auth-scheme=SCHEME  Set HTTP authentication scheme. Currently, BASIC" << endl;
      cout << "                            is the only supported scheme." << endl;
      cout << " -v, --version              Print the version number and exit." << endl;
      cout << " -h, --help                 Print this message and exit." << endl;
      cout << "URL:" << endl;
      cout << " You can specify multiple URLs. All URLs must point to the same file" << endl;
      cout << " or a download fails." << endl;
      cout << "Examples:" << endl;
      cout << " Download a file by 1 connection:" << endl;
      cout << "  aria2c http://AAA.BBB.CCC/file.zip" << endl;
      cout << " Download a file by 2 connections:" << endl;
      cout << "  aria2c -s 2 http://AAA.BBB.CCC/file.zip" << endl;
      cout << " Download a file by 2 connections, each connects to a different server." << endl;
      cout << "  aria2c http://AAA.BBB.CCC/file.zip http://DDD.EEE.FFF/GGG/file.zip" << endl;
      cout << "Reports bugs to <tujikawa at rednoah dot com>" << endl;
    }
     
    int main(int argc, char* argv[]) {
      bool stdoutLog = false;
      string logfile;
      string dir;
      string ufilename;
      int split = 0;
      bool daemonMode = false;
      int c;
     
     
      while(1) {
        int optIndex = 0;
        int lopt;
        static struct option longOpts[] = {
          { "daemon", no_argument, NULL, 'D' },
          { "dir", required_argument, NULL, 'd' },
          { "out", required_argument, NULL, 'o' },
          { "log", required_argument, NULL, 'l' },
          { "split", required_argument, NULL, 's' },
          { "http-proxy", required_argument, &lopt, 1 },
          { "http-user", required_argument, &lopt, 2 },
          { "http-passwd", required_argument, &lopt, 3 },
          { "http-proxy-user", required_argument, &lopt, 4 },
          { "http-proxy-passwd", required_argument, &lopt, 5 },
          { "http-auth-scheme", required_argument, &lopt, 6 },
          { "version", no_argument, NULL, 'v' },
          { "help", no_argument, NULL, 'h' },
          { 0, 0, 0, 0 }
        };
        c = getopt_long(argc, argv, "Dd:o:l:s:vh", longOpts, &optIndex);
        printf("返回值: %c\n",c);
        if(c == -1) {
          break;
        }
        switch(c) {
        case 0:{
          switch(lopt) {
          case 1: {
    	printf("1: %s\n",optarg);
    	break;
          }
          case 2:
    	printf("2: %s\n",optarg);
    	break;
          case 3:
    	printf("3: %s\n",optarg);
    	break;
          case 4:
    	printf("4: %s\n",optarg);
    	break;
          case 5: 
    	printf("5: %s\n",optarg);
    	break;
          case 6:
    	printf("6: %s\n",optarg);
    	break;
          }
          break;
        }
        case 'D':
          printf("D: %s\n",optarg);
          break;
        case 'd':
          printf("d: %s\n",optarg);
          break;
        case 'o':
          printf("o: %s\n",optarg);
          break;
        case 'l':
         printf("l: %s\n",optarg);
          break;
        case 's':
          printf("s: %s\n",optarg);
          break;
        case 'v':
          printf("s: %s\n",optarg);
          //showVersion();
          exit(0);
        case 'h':
          showUsage();
          exit(0);
        default:
          showUsage();
          exit(1);
        }
      }
      return 0;
    }
    

    [参考] : https://blog.csdn.net/qq_33850438/article/details/80172275

  • 相关阅读:
    K2 的Workspace 遭遇400 RequestLength 错误修复
    从APM角度上看:NoSQL和关系数据库并无不同
    Mono的Google Native Client(NaCl)技术支持
    FastReport.Mono 一款为Mono Framework设计的功能全面的报表生成工具
    修改 Windows Host 文件工具
    采用Mono进行移动开发图书推荐
    MonoDevelop添加NuGet支持
    WCF Service Hosting的线程关联性Mono实现比.NET统一?
    [转]WiX v3.7——支持MSBuild、自更新及引用计数
    [转]度量驱动开发
  • 原文地址:https://www.cnblogs.com/1dan/p/15650666.html
Copyright © 2011-2022 走看看