getopt 命令行参数解析

介绍

  • 用来解析命令行参数,argv是一个字符串数组,argc表示这个数组的长度,argv[0]是程序名,所以参数解析是从argv[1]开始。-开始的串表示选项(或者--开始,如果使用长选项),它后面的一个串表示选项的参数(也可能不是,因为选项可以没有参数)
  • 当没有参数解析的时候,函数返回-1
  • man 3 getopt
  • 功能说明
    • getopt: 获取短参数,它可以获取-a-l类型的短参数,也可以-al合并的获取到al
    • getopt_long: 在getopt的基础上获取长参数,它还可以获取--help这种参数
    • getopt_long_only: 也是在上一个函数基础上有所增加,输入长参数可以不用输入两个--,而是可以直接用-help

SYNOPSIS

  • #include <unistd.h>

    • int getopt(int argc, char * const argv[],const char *optstring);
    • extern char *optarg; 存储选项的参数
    • extern int optind, opterr, optopt;
      • optind 是argv的下标,argv[optind]表示下一个待解析的参数,optind初始值为1
      • opterr 是否显示错误信息,非零显示,0不显示,一般我们把它设为0
      • optopt 如果出现错误,保存出错的那个选项
  • #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)

参数说明

  • argcargv 就是传递给main函数的两个参数,argv就是程序运行时的程序名以及它的参数,是一个字符串数组,argc就是这个字符串数组的长度
  • optstring 指定需要解析的短参数,比如"abc:d:e::"表示有abcde这5种参数,而且ab不带参数,c带参数(后面跟的:表示后面必须跟一个参数),e可带可不带参数(后面跟的::表示选项参数是可选的,如果带参数必须紧挨着选项,也就是-exxx,不能有空格隔开如-e xxx,隔开则视为没有带参数),选项参数由optarg指向
  • longopts 指向option数组,包含了长选项的信息,数组最后一个元素(结构体)必须全部为0,下一节详细介绍这个结构体
  • longindex 如果不是null,那么将解析参数时将把它指向的变量设为对应的longopts数组的下标

option结构体

struct option {
    const char *name;    // --<name> name of the long option
    int         has_arg; // no_argument (or 0), required_argument (or 1), optional_argument (or 2)
    int        *flag;    // set *flag to val and returns 0 if not null
    int         val;     // value to return or to load into *flag
}
  • name 表示长选项的名字,使用时就是用--<name>的形式
  • has_arg 用来指示这个选项的参数要求,no_argument或者0表示不带参数,required_argument或者1表示必须带参数,optional_argument或者2表示参数是可选的(可选的参数要带参数的话必须是--opt=param形式,不能用空格隔开,要用等于)
  • flag 通常设为0,若不为0,那么解析参数时将会把*flag设置为val,然后函数返回0
  • val 解析到参数时函数返回的值,或者设置*flag的值,通常把它设为对应的短参数字符

错误参数处理

两种错误,一个是出现不认识的选项,另一个是需要带参数的选项没有带参数

  • 默认情况,遇到错误,输出错误信息,把出错的那个选项保存到optopt,然后返回?
  • 如果opterr设为了0,则不输出错误信息,可以通过是否返回?来判定是否出错(默认情况opterr非0)
  • 如果optstring的第一个字符(也可能是第二个,如果开头有+-的话)是:,那么也不会输出错误信息,然后会返回:表示缺少选项参数或者返回?表示出现不认识的选项(这样就能把两种错误区分开了)

使用getopt

示例代码getopt-test.c

// getopt-test.c
// gcc -g -o getopt-test getopt-test.c
#include <getopt.h>
#include <stdio.h>

int main(int argc, char *const argv[]) {
  char c;
  while ((c = getopt(argc, argv, "abc:d::")) != -1) {
    //   while ((c = getopt(argc, argv, ":abc:d::")) != -1) {
    switch (c) {
      case 'a':
      case 'b':
        printf("got %c\n", c);
        break;
      case 'c':
        puts("got 'c'");
        printf("argument for c is: %s\n", optarg);
        break;
      case 'd':
        puts("got d");
        if (optarg) {
          printf("argument for d is: %s\n", optarg);
        } else {
          puts("no argument for d");
        }
        break;
      default:
        printf("got %d (%c), optopt: %d (%c)\n", c, c, optopt, optopt);
        break;
    }
  }
  return 0;
}

运行情况

  • optstring前面不带:
> ./getopt-test -d -d123 -c 456 -afc
got d
no argument for d
got d
argument for d is: 123
got 'c'
argument for c is: 456
got a
./getopt-test: invalid option -- 'f'
got 63 (?), optopt: 102 (f)
./getopt-test: option requires an argument -- 'c'
got 63 (?), optopt: 99 (c)

当遇到解析参数错误时(也就是上面说的两种错误),会输出错误提示,而且返回的字符都是?

  • optstring前面带:时,同样的命令
> ./getopt-test -d -d123 -c 456 -afc
got d
no argument for d
got d
argument for d is: 123
got 'c'
argument for c is: 456
got a
got 63 (?), optopt: 102 (f)
got 58 (:), optopt: 99 (c)

这样可以区分出是哪一种错误(如果你需要的话),而且不会输出错误信息

  • 另外如果将opterr设为0的话也不会输出错误信息

使用getopt_long

示例代码getopt_long-test.c

// getopt_long-test.c
// gcc -g -o getopt_long-test getopt_long-test.c
// ./getopt_long-test -e s --name sky --delete 123 -d123 --delete=123 --new --add -fe
#include <getopt.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *const argv[]) {
  char c;
  //   opterr = 0;
  int ret, longind;
  struct option long_options[] = {{"add", no_argument, 0, 'a'},
                                  {"new", no_argument, 0, 'n'},
                                  {"name", required_argument, 0, 256},
                                  {"create", required_argument, 0, 'c'},
                                  {"delete", optional_argument, 0, 'd'},
                                  {0, 0, 0, 0}};
  while ((ret = getopt_long(argc, argv, "anc:e:d::", long_options, &longind)) != -1) {
//   while ((ret = getopt_long(argc, argv, ":anc:e:d::", long_options, &longind)) != -1) {
    switch (ret) {
      case 'a':
        printf("got 'a', longind is: %d\n", longind);
        break;
      case 'n':
        printf("got 'n', longind is: %d\n", longind);
        break;
      case 256:
        printf("%s %s\n", long_options[longind].name, optarg);
        break;
      case 'c':
        printf("got 'c', longind is: %d\n", longind);
        break;
      case 'd':
        printf("got 'd', longind is: %d\n", longind);
        if (optarg) {
          printf("optional argument is: %s\n", optarg);
        } else {
          printf("no argument\n");
        }
        break;
      case 'e':
        printf("got 'e' -- %s\n", optarg);
        break;
      default:
        printf("got %d (%c), optopt: %d (%c)\n", c, c, optopt, optopt);
        break;
    }
  }
  return 0;
}

运行情况

TODO, 有些问题,我试验时,遇到错误参数不会返回:或者?,总是返回0,这和文档不一致,还没搞清楚原因是什么

more

  • shell中的getopt -- todo
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容