• 注册
  • 后端开发博客 后端开发博客 关注:0 内容:2416

    命令行解析函数:getopt_long、getopt

  • 查看作者
  • 打赏作者
  • 当前位置: 职业司 > 后端开发 > 后端开发博客 > 正文
    • 后端开发博客
    • 一、前言

      在学习一些项目代码时,尤其涉及到命令行传参的代码,经常遇到getopt相关的函数,对这一类函数可以说是既陌生又熟悉。陌生是因为不知道它是干啥的,熟悉呢,是因为经常遇到。于是乎在追踪了多天ipsec配置文件解析流程之后,准备学习下这一类命令行解析利器。

      这么多命令行参数,需要解析,想象都让人头大,如果再没有一个好的解析方式,那就雪上加霜了。辛亏有了一类命令行解析函数,可以让这些解析操作变得容易一点点。下面就简单的介绍下这一类函数,主要有getopt、getopt_long、getopt_long_only。

      Man 手册信息如下:

      NAME
      getopt, getopt_long, getopt_long_only, optarg, optind, opterr, optopt - Parse command-line options
      SYNOPSIS
      #include <unistd.h>
      int getopt(int argc, char * const argv[],
      const char *optstring);
      extern char *optarg;
      extern int optind, opterr, 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);
      复制代码

      先从最简单的,最基本的getopt函数开始。然后再介绍增强版的getopt_long函数。

      二、getopt函数

      2.1 函数简介:

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

      各项参数解释如下:

      函数功能

      用来解析命令行选项参数,只适用于短选项:-d /root; 不能解析长选项--arch, --help等

      Argc

      通过命令行传给main函数参数的个数

      argv

      通过命令行传给main函数参数组成的字符串指针数组

      optstring

      选项字符串。用来告诉getopt可以解析哪些选项,哪些选项需要参数以及函数返回值等(字符后面紧跟一个冒号则需要参数,而两个则表示参数可选)

      返回值

      如果成功返回选项字母;命令行解析完毕返回-1;如果选项未定义,则提示错误信息,并返回'?';如果参数缺失,第一个字符是':'则返回':', 否则返回'?'

      对于optstring字符串格式做一个简单说明:

      单个字符,表示没有参数

      单个字符紧跟1个冒号,表示必须有参数**,格式:-d xxx或者-dxxx**

      单个字符紧跟2个冒号,表示参数可选**,格式:-dxxx**

      Char *optstring="ab:c::";

      说明:此选项指定了三个选项,分别为'a'、'b'、'c'。其中

      a选项无需参数,格式:-a即可

      b选项必须有参数,格式:-d xxx

      c选项参数可选,格式:-c ooo

      在此类函数中,需要几个重要的变量共同配合才能完成命令行参数解析工作:

      变量名称

      作用

      Char *optarg

      指向当前选项参数的指针

      Int optind

      用来记录当前已遍历选项的索引,方便下次调用时直接找到下一个选项

      Int opterr

      正常情况,解析失败会有错误信息,如果不需要此错误信息,将opterr置0即可

      Int optopt

      最后一个未知选项

      2.2 举例说明:

      代码如下:

      /*************************************************************************
      > File Name: getopt.c
      > Author: Toney
      > Mail: vip_13031075266@163.com
      > Created Time: 2021年01月30日 星期六 21时50分45秒
      ************************************************************************/
      #include <stdio.h>
      #include <unistd.h>
      #include <getopt.h>
      void main(int argc, char **argv)
      {
      int flags, opt;
      while((opt = getopt(argc, argv, "ab:c::")) != -1){
      switch(opt){
      case 'a':
      printf("Input %d parameter is -a=%s\n", optind, optarg);
      break;
      case 'b':
      printf("Input %d parameter is -b=%s\n", optind, optarg);
      break;
      case 'c':
      printf("Input %d parameter is -c=%s\n", optind, optarg);
      break;
      default:
      printf("Not match!!!");
      }
      }
      return ;
      }
      复制代码

      命令行解析函数:getopt_long、getopt

      三、getopt_long函数

      3.1 函数简介:

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

      各项参数解释如下:

      函数功能

      用来解析命令行选项参数,除了getopt函数支持的短选项,还支持长选项,如--help, --prefix

      Argc

      通过命令行传给main函数参数的个数

      argv

      通过命令行传给main函数参数组成的字符串指针数组

      optstring

      选项字符串。用来告诉getopt可以解析哪些选项,哪些选项需要参数以及函数返回值等(字符后面紧跟一个冒号则需要参数,而两个则表示参数可选)

      longopts

      长选项参数的名称、属性、以及解析后的返回值等结构信息

      longindex

      用来记录解析到的当前长选项的索引,也就是longopts的下标。

      返回值

      对于短选项,返回值同getopt函数;对于长选项,如果flag是NULL,返回val,否则返回0;对于错误情况返回值同getopt函数

      Struct option结构体:

      struct option {
      const char *name; /* 参数名称 */
      int has_arg; /* 指明是否带有参数 */
      int *flag; /* flag=NULL时,返回value;不为空时,*flag=val,返回0 */
      int val; /* 用于指定函数找到选项的返回值或flag非空时指定*flag的值 */
      };

      其中has_arg类型取值有如下几种:

      No_argument

      不需要参数

      Required_argument

      必须带参数

      Optional_argument

      参数可选

      在此类函数中,需要几个重要的变量共同配合才能完成命令行参数解析工作:

      变量名称

      作用

      Char *optarg

      指向当前选项参数的指针

      Int optind

      用来记录当前已遍历选项的索引,方便下次调用时直接找到下一个选项

      Int opterr

      正常情况,解析失败会有错误信息,如果不需要此错误信息,将opterr置0即可

      Int optopt

      最后一个未知选项

      3.2 ipsec****项目中的一个例子:

      先看看在openswan源码中,有关使用getopt_long解析命令行的一个例子(各位把住坐稳了):

      static const struct option long_opts[] = {
      #   define OO	OPTION_OFFSET
      /* name, has_arg, flag, val */
      { "help", no_argument, NULL, 'h' },
      { "version", no_argument, NULL, 'v' },
      { "optionsfrom", required_argument, NULL, '+' },
      { "label", required_argument, NULL, 'l' },
      { "ctlbase", required_argument, NULL, OPT_CTLBASE + OO },
      { "name", required_argument, NULL, OPT_NAME + OO },
      { "connalias", required_argument, NULL, OPT_CONNALIAS + OO },
      { "keyid", required_argument, NULL, OPT_KEYID + OO },
      { "addkey", no_argument, NULL, OPT_ADDKEY + OO },
      { "pubkeyrsa", required_argument, NULL, OPT_PUBKEYRSA + OO },
      { "myid", required_argument, NULL, OPT_MYID + OO },
      { "route", no_argument, NULL, OPT_ROUTE + OO },
      { "unroute", no_argument, NULL, OPT_UNROUTE + OO },
      { "initiate", no_argument, NULL, OPT_INITIATE + OO },
      { "terminate", no_argument, NULL, OPT_TERMINATE + OO },
      { "delete", no_argument, NULL, OPT_DELETE + OO },
      { "deletestate", required_argument, NULL, OPT_DELETESTATE + OO + NUMERIC_ARG },
      { "crash", required_argument, NULL, OPT_DELETECRASH + OO },
      { "listen", no_argument, NULL, OPT_LISTEN + OO },
      { "unlisten", no_argument, NULL, OPT_UNLISTEN + OO },
      { "purgeocsp", no_argument, NULL, OPT_PURGEOCSP + OO },
      { "rereadsecrets", no_argument, NULL, OPT_REREADSECRETS + OO },
      { "rereadcacerts", no_argument, NULL, OPT_REREADCACERTS + OO },
      { "rereadaacerts", no_argument, NULL, OPT_REREADAACERTS + OO },
      { "rereadocspcerts", no_argument, NULL, OPT_REREADOCSPCERTS + OO },
      { "rereadacerts", no_argument, NULL, OPT_REREADACERTS + OO },
      { "rereadcrls", no_argument, NULL, OPT_REREADCRLS + OO },
      { "rereadall", no_argument, NULL, OPT_REREADALL + OO },
      { "status", no_argument, NULL, OPT_STATUS + OO },
      { "shutdown", no_argument, NULL, OPT_SHUTDOWN + OO },
      { "xauthname", required_argument, NULL, OPT_XAUTHNAME + OO },
      { "xauthuser", required_argument, NULL, OPT_XAUTHNAME + OO },
      { "xauthpass", required_argument, NULL, OPT_XAUTHPASS + OO },
      { "tpmeval",   required_argument, NULL, OPT_TPMEVAL   + OO },
      { "oppohere", required_argument, NULL, OPT_OPPO_HERE + OO },
      { "oppothere", required_argument, NULL, OPT_OPPO_THERE + OO },
      { "asynchronous", no_argument, NULL, OPT_ASYNC + OO },
      /* list options */
      { "utc", no_argument, NULL, LST_UTC + OO },
      { "checkpubkeys", no_argument, NULL, LST_CHECKPUBKEYS + OO },
      { "listpubkeys", no_argument, NULL, LST_PUBKEYS + OO },
      { "listcerts", no_argument, NULL, LST_CERTS + OO },
      { "listcacerts", no_argument, NULL, LST_CACERTS + OO },
      { "listacerts", no_argument, NULL, LST_ACERTS + OO },
      { "listaacerts", no_argument, NULL, LST_AACERTS + OO },
      { "listocspcerts", no_argument, NULL, LST_OCSPCERTS + OO },
      { "listgroups", no_argument, NULL, LST_GROUPS + OO },
      { "listcrls", no_argument, NULL, LST_CRLS + OO },
      { "listocsp", no_argument, NULL, LST_OCSP + OO },
      { "listpsks", no_argument, NULL, LST_PSKS + OO },
      { "listevents", no_argument, NULL, LST_EVENTS + OO },
      { "listpairs",     no_argument, NULL, LST_HOSTPAIRS + OO },
      { "listhostpairs", no_argument, NULL, LST_HOSTPAIRS + OO },
      { "listall", no_argument, NULL, LST_ALL + OO },
      /* options for an end description */
      { "host", required_argument, NULL, END_HOST + OO },
      { "id", required_argument, NULL, END_ID + OO },
      { "cert", required_argument, NULL, END_CERT + OO },
      { "ca", required_argument, NULL, END_CA + OO },
      { "groups", required_argument, NULL, END_GROUPS + OO },
      { "ikeport", required_argument, NULL, END_IKEPORT + OO + NUMERIC_ARG },
      { "nexthop", required_argument, NULL, END_NEXTHOP + OO },
      { "client", required_argument, NULL, END_CLIENT + OO },
      { "clientwithin", required_argument, NULL, END_CLIENTWITHIN + OO },
      { "clientprotoport", required_argument, NULL, END_CLIENTPROTOPORT + OO },
      { "dnskeyondemand", no_argument, NULL, END_DNSKEYONDEMAND + OO },
      { "srcip",  required_argument, NULL, END_SRCIP + OO },
      { "updown", required_argument, NULL, END_UPDOWN + OO },
      { "tundev", required_argument, NULL, END_TUNDEV + OO + NUMERIC_ARG },
      /* options for a connection description */
      { "to", no_argument, NULL, CD_TO + OO },
      { "psk", no_argument, NULL, CD_PSK + OO },
      { "rsasig", no_argument, NULL, CD_RSASIG + OO },
      { "encrypt", no_argument, NULL, CD_ENCRYPT + OO },
      { "authenticate", no_argument, NULL, CD_AUTHENTICATE + OO },
      { "compress",  no_argument, NULL, CD_COMPRESS + OO },
      { "overlapip", no_argument, NULL, CD_OVERLAPIP + OO },
      { "tunnel", no_argument, NULL, CD_TUNNEL + OO },
      { "tunnelipv4", no_argument, NULL, CD_TUNNELIPV4 + OO },
      { "tunnelipv6", no_argument, NULL, CD_TUNNELIPV6 + OO },
      { "pfs", no_argument, NULL, CD_PFS + OO },
      { "sha2_truncbug", no_argument, NULL, CD_SHA2_TRUNCBUG + OO },
      { "aggrmode", no_argument, NULL, CD_AGGRESSIVE + OO },
      { "disablearrivalcheck", no_argument, NULL, CD_DISABLEARRIVALCHECK + OO },
      { "initiateontraffic", no_argument, NULL
      , CD_SHUNT0 + (POLICY_SHUNT_TRAP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
      { "pass", no_argument, NULL
      , CD_SHUNT0 + (POLICY_SHUNT_PASS >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
      { "drop", no_argument, NULL
      , CD_SHUNT0 + (POLICY_SHUNT_DROP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
      { "reject", no_argument, NULL
      , CD_SHUNT0 + (POLICY_SHUNT_REJECT >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO },
      { "failnone", no_argument, NULL
      , CD_FAIL0 + (POLICY_FAIL_NONE >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
      { "failpass", no_argument, NULL
      , CD_FAIL0 + (POLICY_FAIL_PASS >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
      { "faildrop", no_argument, NULL
      , CD_FAIL0 + (POLICY_FAIL_DROP >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
      { "failreject", no_argument, NULL
      , CD_FAIL0 + (POLICY_FAIL_REJECT >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO },
      { "dontrekey", no_argument, NULL, CD_DONT_REKEY + OO },
      { "forceencaps", no_argument, NULL, CD_FORCEENCAPS + OO },
      { "dpddelay", required_argument, NULL, CD_DPDDELAY + OO + NUMERIC_ARG },
      { "dpdtimeout", required_argument, NULL, CD_DPDTIMEOUT + OO + NUMERIC_ARG },
      { "dpdaction", required_argument, NULL, CD_DPDACTION + OO },
      #ifdef XAUTH
      { "xauth", no_argument, NULL, END_XAUTHSERVER + OO },
      { "xauthserver", no_argument, NULL, END_XAUTHSERVER + OO },
      { "xauthclient", no_argument, NULL, END_XAUTHCLIENT + OO },
      #endif
      #ifdef MODECFG
      { "modecfgpull",   no_argument, NULL, CD_MODECFGPULL + OO },
      { "modecfgserver", no_argument, NULL, END_MODECFGSERVER + OO },
      { "modecfgclient", no_argument, NULL, END_MODECFGCLIENT + OO },
      #ifdef MODECFG_DNSWINS
      { "modecfgdns1", required_argument, NULL, CD_MODECFGDNS1 + OO },
      { "modecfgdns2", required_argument, NULL, CD_MODECFGDNS2 + OO },
      { "modecfgwins1", required_argument, NULL, CD_MODECFGWINS1 + OO },
      { "modecfgwins2", required_argument, NULL, CD_MODECFGWINS2 + OO },
      { "modeconfigserver", no_argument, NULL, END_MODECFGSERVER + OO },
      { "modeconfigclient", no_argument, NULL, END_MODECFGCLIENT + OO },
      #endif
      #endif
      { "metric", required_argument, NULL, CD_METRIC + OO + NUMERIC_ARG },
      { "mtu", required_argument, NULL, CD_CONNMTU + OO + NUMERIC_ARG },
      { "sendcert", required_argument, NULL, END_SENDCERT + OO },
      { "certtype", required_argument, NULL, END_CERTTYPE + OO + NUMERIC_ARG },
      { "ipv4", no_argument, NULL, CD_CONNIPV4 + OO },
      { "ipv6", no_argument, NULL, CD_CONNIPV6 + OO },
      { "ikelifetime", required_argument, NULL, CD_IKELIFETIME + OO + NUMERIC_ARG },
      { "ipseclifetime", required_argument, NULL, CD_IPSECLIFETIME + OO + NUMERIC_ARG },
      { "rekeymargin", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG },
      { "rekeywindow", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG },	/* OBSOLETE */
      { "rekeyfuzz", required_argument, NULL, CD_RKFUZZ + OO + NUMERIC_ARG },
      { "keyingtries", required_argument, NULL, CD_KTRIES + OO + NUMERIC_ARG },
      { "ike",    required_argument, NULL, CD_IKE + OO },
      { "ikealg", required_argument, NULL, CD_IKE + OO },
      { "pfsgroup", required_argument, NULL, CD_PFSGROUP + OO },
      { "esp", required_argument, NULL, CD_ESP + OO },
      { "remote_peer_type", required_argument, NULL, CD_REMOTEPEERTYPE + OO},
      #ifdef HAVE_NM
      { "nm_configured", no_argument, NULL, CD_NMCONFIGURED + OO},
      #endif
      #ifdef HAVE_LABELED_IPSEC
      { "loopback", no_argument, NULL, CD_LOOPBACK + OO},
      { "labeledipsec", no_argument, NULL, CD_LABELED_IPSEC + OO},
      { "policylabel", required_argument, NULL, CD_POLICY_LABEL + OO },
      #endif
      #ifdef DEBUG
      { "debug-none", no_argument, NULL, DBGOPT_NONE + OO },
      { "debug-all", no_argument, NULL, DBGOPT_ALL + OO },
      { "debug-raw", no_argument, NULL, DBGOPT_RAW + OO },
      { "debug-crypt", no_argument, NULL, DBGOPT_CRYPT + OO },
      { "debug-parsing", no_argument, NULL, DBGOPT_PARSING + OO },
      { "debug-emitting", no_argument, NULL, DBGOPT_EMITTING + OO },
      { "debug-control", no_argument, NULL, DBGOPT_CONTROL + OO },
      { "debug-lifecycle", no_argument, NULL, DBGOPT_LIFECYCLE + OO },
      { "debug-klips",  no_argument, NULL, DBGOPT_KLIPS + OO },
      { "debug-netkey", no_argument, NULL, DBGOPT_KLIPS + OO },
      { "debug-xfrm",   no_argument, NULL, DBGOPT_KLIPS + OO },
      { "debug-dns", no_argument, NULL, DBGOPT_DNS + OO },
      { "debug-oppo", no_argument, NULL, DBGOPT_OPPO + OO },
      { "debug-oppoinfo", no_argument, NULL, DBGOPT_OPPOINFO + OO },
      { "debug-whackwatch",  no_argument, NULL, DBGOPT_WHACKWATCH + OO },
      { "debug-controlmore", no_argument, NULL, DBGOPT_CONTROLMORE + OO },
      { "debug-pfkey",   no_argument, NULL, DBGOPT_PFKEY + OO },
      { "debug-nattraversal", no_argument, NULL, DBGOPT_NATT + OO },
      { "debug-natt",    no_argument, NULL, DBGOPT_NATT + OO },
      { "debug-nat_t",   no_argument, NULL, DBGOPT_NATT + OO },
      { "debug-nat-t",   no_argument, NULL, DBGOPT_NATT + OO },
      { "debug-x509",    no_argument, NULL, DBGOPT_X509 + OO },
      { "debug-dpd",     no_argument, NULL, DBGOPT_DPD + OO },
      { "debug-private", no_argument, NULL, DBGOPT_PRIVATE + OO },
      { "impair-delay-adns-key-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER + OO },
      { "impair-delay-adns-txt-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER + OO },
      { "impair-bust-mi2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MI2 + OO },
      { "impair-bust-mr2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MR2 + OO },
      { "impair-sa-fail",    no_argument, NULL, DBGOPT_IMPAIR_SA_CREATION + OO },
      { "impair-die-oninfo", no_argument, NULL, DBGOPT_IMPAIR_DIE_ONINFO  + OO },
      { "impair-jacob-two-two", no_argument, NULL, DBGOPT_IMPAIR_JACOB_TWO_TWO + OO },
      { "impair-major-version-bump", no_argument, NULL, DBGOPT_IMPAIR_MAJOR_VERSION_BUMP + OO },
      { "impair-minor-version-bump", no_argument, NULL, DBGOPT_IMPAIR_MINOR_VERSION_BUMP + OO },
      { "impair-retransmits", no_argument, NULL, DBGOPT_IMPAIR_RETRANSMITS + OO },
      { "impair-send-bogus-isakmp-flag", no_argument, NULL, DBGOPT_IMPAIR_SEND_BOGUS_ISAKMP_FLAG + OO },
      { "whackrecord",     required_argument, NULL, OPT_WHACKRECORD + OO},
      { "whackstoprecord", no_argument, NULL, OPT_WHACKSTOPRECORD + OO},
      #endif
      #   undef OO
      { 0,0,0,0 }
      };
      复制代码

      这是whack命令解析时的一个结构信息,可以想象它的配置命令是有多少,而具体实现差不多800行左右的C代码。这里需要注意的是:struct option结构中的val取值通常是单个字符或者数字。由于单字符数量有限,参数比较少时可以使用字符,但是如果像上面辣么多参数,通常采用枚举类型,方便扩展。

      四、getopt_long_only函数

      getopt_long_only 函数与 getopt_long 函数使用相同的参数表,在功能上基本一致,只是 getopt_long 只将 --name 当作长参数,但 getopt_long_only 会将 --name 和 -name 两种选项都当作长参数来匹配。getopt_long_only 如果选项 -name 不能在 longopts 中匹配,但能匹配一个短选项,它就会解析为短选项。

      请登录之后再进行评论

      登录

      手机阅读天地(APP)

      • 微信公众号
      • 微信小程序
      • 安卓APP
      手机浏览,惊喜多多
      匿名树洞,说我想说!
      问答悬赏,VIP可见!
      密码可见,回复可见!
      即时聊天、群聊互动!
      宠物孵化,赠送礼物!
      动态像框,专属头衔!
      挑战/抽奖,金币送不停!
      赶紧体会下,不会让你失望!
    • 实时动态
    • 签到
    • 做任务
    • 发表内容
    • 偏好设置
    • 到底部
    • 帖子间隔 侧栏位置:
    • 还没有账号?点这里立即注册