命令行选项解析函数(C语言):getopt()和getopt_long()

上午在看源码项目webbench时,刚开始就被一个似乎挺陌生函数getopt_long()给卡住了,说实话这函数没怎么见过,自然不知道这哥们是干什么的。于是乎百度了一番,原来是处理命令行选项参数的,的确,正规点的大型程序一般第一步就是处理命令行参数的,接着才是主干程序。在百度和man的帮助下,找到了具体使用方法和解释,二话不说赶紧学习一下,并总结出文档记录一下。

平时在写程序时常常需要对命令行参数进行处理,因为参数少,自己解析就可以搞定;如果命令行个数比较多时,如果按照顺序一个一个定义参数含义很容易造成混乱,而且如果程序只按顺序处理参数的话,一些“可选参数”的功能将很难实现,这个问题在linux中用getopt等函数可以优雅地解决。

查询linux命令手册:man 3 getopt_long:

<span style="font-size:14px;">#include<unistd.h>
#include<getopt.h>          /*所在头文件 */
int getopt(intargc, 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);
extern char *optarg;         /*系统声明的全局变量 */
extern int optind, opterr, optopt;</span>

先拿最简单的getopt函数开刀,getopt_long只是前者的增强版,功能多点而已。

(1) getopt函数

定义int getopt(int argc, char * const argv[], const char *optstring);
描述
:getopt是用来解析命令行选项参数的,但是只能解析短选项: -d 100,不能解析长选项:--prefix
参数:argc:main()函数传递过来的参数的个数
             argv:main()函数传递过来的参数的字符串指针数组
             optstring:选项字符串,告知 getopt()可以处理哪个选项以及哪个选项需要参数
返回:如果选项成功找到,返回选项字母;如果所有命令行选项都解析完毕,返回-1;如果遇到选项字符不在optstring中,返回字符’?’;如果遇到丢失参数,那么返回值依赖于optstring中第一个字符,如果第一个字符是’:’则返回’:’,否则返回’?’并提示出错误信息。

下边重点举例说明optstring的格式意义:

char*optstring = “ab:c::”;
单个字符a
           表示选项a没有参数             格式:-a即可,不加参数
单字符加冒号b:      表示选项b有且必须加参数       格式:-b 100或-b100,但-b=100错
冒号c::   表示选项c可以有,也可以无     格式:-c200,其它格式错误

上面这个optstring在传入之后,getopt函数将依次检查命令行是否指定了 -a, -b, -c(这需要多次调用getopt函数,直到其返回-1),当检查到上面某一个参数被指定时,函数会返回被指定的参数名称(即该字母)

optarg —— 指向当前选项参数(如果有)的指针。
optind —— 再次调用 getopt() 时的下一个 argv指针的索引。
optopt —— 最后一个未知选项。
opterr ­—— 如果不希望getopt()打印出错信息,则只要将全域变量opterr设为0即可。

以上描述的并不生动,下边结合实例来理解:

实例:

<span style="font-size:14px;">#include<stdio.h>
#include<unistd.h>
#include<getopt.h>
int main(intargc, char *argv[])
{
    int opt;
    char *string = "a::b:c:d";
    while ((opt = getopt(argc, argv, string))!= -1)
    {
        printf("opt = %c\t\t", opt);
        printf("optarg = %s\t\t",optarg);
        printf("optind = %d\t\t",optind);
        printf("argv[optind] = %s\n",argv[optind]);
    }
}</span>

编译上述程序并执行结果:

、输入选项及参数正确的情况

<span style="font-size:14px;">dzlab:~/test/test#./opt -a100 -b 200 -c 300 -d
opt = a         optarg = 100            optind = 2              argv[optind] = -b
opt = b         optarg = 200            optind = 4              argv[optind] = -c
opt = c         optarg = 300            optind = 6              argv[optind] = -d
opt = d         optarg = (null)         optind = 7              argv[optind] = (null)</span>

或者这样的选项格式(注意区别):

dzlab:~/test/test#./opt -a100 -b200 -c300 -d
opt = a         optarg = 100            optind = 2              argv[optind] = -b200
opt = b         optarg = 200            optind = 3              argv[optind] = -c300
opt = c         optarg = 300            optind = 4              argv[optind] = -d
opt = d         optarg = (null)         optind = 5              argv[optind] = (null)

选项a是可选参数,这里不带参数也是正确的

dzlab:~/test/test#./opt -a -b 200 -c 300 -d
opt = a         optarg = (null)         optind = 2              argv[optind] = -b
opt = b         optarg = 200            optind = 4              argv[optind] = -c
opt = c         optarg = 300            optind = 6              argv[optind] = -d
opt = d         optarg = (null)         optind = 7              argv[optind] = (null)

、输入选项参数错误的情况

dzlab:~/test/test#./opt -a 100 -b 200 -c 300 -d
opt = a         optarg = (null)         optind = 2              argv[optind] = 100
opt = b         optarg = 200            optind = 5              argv[optind] = -c
opt = c         optarg = 300            optind = 7              argv[optind] = -d
opt = d         optarg = (null)         optind = 8              argv[optind] = (null)

导致解析错误,第一个optarg = null,实际输入参数100,由于格式不正确造成的(可选参数格式固定)

参数丢失,也会导致错误,c选项是必须有参数的,不加参数提示错误如下:

dzlab:~/test/test#./opt -a -b 200 -c
opt = a         optarg = (null)         optind = 2              argv[optind] = -b
opt = b         optarg = 200            optind = 4              argv[optind] = -c
./opt: optionrequires an argument -- 'c'
opt = ?         optarg = (null)         optind = 5              argv[optind] = (null)

这种情况,optstring中第一个字母不是’:’,如果在optstring中第一个字母加’:’,则最后丢失参数的那个选项opt返回的是’:’,不是’?’,并且没有提示错误信息,这里不再列出。

命令行选项未定义,-e选项未在optstring中定义,会报错:

dzlab:~/test/test#./opt -a -b 200 -e
opt = a         optarg = (null)         optind = 2              argv[optind] = -b
opt = b         optarg = 200             optind = 4              argv[optind] = -e
./opt: invalidoption -- 'e'
opt = ?         optarg = (null)         optind = 5              argv[optind] = (null)

到这里应该已经把getopt函数的功能讲解清楚了吧,下边来说说getopt_long函数,getopt_long函数包含了getopt函数的功能,并且还可以指定“长参数”(或者说长选项),与getopt函数对比,getopt_long比其多了两个参数:

(2) getopt_long函数

定义:int getopt_long(int argc, char * const argv[], const char *optstring,

const struct option *longopts,int *longindex);

描述:包含getopt功能,增加了解析长选项的功能如:--prefix --help

参数:longopts    指明了长参数的名称和属性

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

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

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

has_arg  指明是否带参数值,其数值可选:

no_argument         表明长选项不带参数,如:--name, --help
required_argument  表明长选项必须带参数,如:--prefix /root或 --prefix=/root
optional_argument  表明长选项的参数是可选的,如:--help或 –prefix=/root,其它都是错误

接着看一下实例操作会更加深刻地理解:

实例

int main(intargc, char *argv[])
{
    int opt;
    int digit_optind = 0;
    int option_index = 0;
    char *string = "a::b:c:d";
    static struct option long_options[] =
    {
        {"reqarg", required_argument,NULL, 'r'},
        {"optarg", optional_argument,NULL, 'o'},
        {"noarg",  no_argument,         NULL,'n'},
        {NULL,     0,                      NULL, 0},
    };
    while((opt =getopt_long_only(argc,argv,string,long_options,&option_index))!= -1)
    {
        printf("opt = %c\t\t", opt);
        printf("optarg = %s\t\t",optarg);
        printf("optind = %d\t\t",optind);
        printf("argv[optind] =%s\t\t", argv[optind]);
        printf("option_index = %d\n",option_index);
    }
}

编译上述程序并执行结果:

、正确输入长选项的情况

dzlab:~/test/test#./long --reqarg 100 --optarg=200 --noarg
opt = r optarg =100     optind = 3   argv[optind] = --optarg=200  option_index = 0
opt = o optarg =200     optind = 4   argv[optind] = --noarg        option_index = 1
opt = n optarg =(null) optind = 5    argv[optind] =(null)          option_index = 2

或者这种方式:

dzlab:~/test/test#./long –reqarg=100 --optarg=200 --noarg
opt = r optarg =100     optind = 2   argv[optind] = --optarg=200  option_index = 0
opt = o optarg =200     optind = 3   argv[optind] = --noarg        option_index = 1
opt = n optarg =(null) optind = 4    argv[optind] =(null)          option_index = 2

可选选项可以不给参数

dzlab:~/test/test#./long --reqarg 100 --optarg --noarg
opt = r optarg =100     optind = 3     argv[optind] = --optarg option_index = 0
opt = o optarg =(null) optind = 4      argv[optind] =--noarg   option_index = 1
opt = n optarg =(null) optind = 5      argv[optind] =(null)     option_index = 2

、输入长选项错误的情况

dzlab:~/test/test#./long --reqarg 100 --optarg 200 --noarg
opt = r optarg =100     optind = 3     argv[optind] = --optarg  option_index= 0
opt = o optarg =(null) optind = 4      argv[optind] =200        option_index = 1
opt = n optarg =(null) optind = 6      argv[optind] =(null)     option_index = 2

这时,虽然没有报错,但是第二项中optarg参数没有正确解析出来(格式应该是—optarg=200)

必须指定参数的选项,如果不给参数,同样解析错误如下:

dzlab:~/test/test#./long --reqarg --optarg=200 --noarg
opt = r optarg =--optarg=200  optind = 3 argv[optind] =--noarg  option_index = 0
opt = n optarg =(null)         optind = 4 argv[optind] =(null)    option_index = 2

长选项的举例说明暂且就这么多吧,其它如选项错误、缺参数、格式不正确的情况自己再试验一下。

(3) getopt_long_only函数

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

版权声明:本文为博主原创文章,未经博主允许不得转载。

命令行选项解析函数(C语言):getopt()和getopt_long()的更多相关文章

  1. NUnit-Console 命令行选项详解

    本文为 Dennis Gao 原创或翻译技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. NUnit-Console 命令行选项 NUnit-Console 命令行选项列表 指定运行哪 ...

  2. python argparse模块解析命令行选项简单使用

    argparse模块的解析命令行选项简单使用 util.py #!/usr/bin/env python # coding=utf-8 import argparse parser = argpars ...

  3. argparse - 命令行选项与参数解析(转)

    argparse - 命令行选项与参数解析(译)Mar 30, 2013 原文:argparse – Command line option and argument parsing 译者:young ...

  4. bash shell命令行选项与修传入参数处理

    在编写shell程序时经常需要处理命令行参数,本文描述在bash下的命令行处理方式.选项与参数:如下命令行: ./test.sh -f config.conf -v --prefix=/home -f ...

  5. Linux命令行选项及参数

    1.main函数参数形式 int main(int argc , char *argv[] , char *env[]); //第一个参数argc代表命令行的参数个数 //第二个参数依次指向各个参数, ...

  6. 脚本乐园 Shell中命令行选项和参数的处理

    在Linux的Shell中怎样处理tail -n 10 access.log这样的命令行选项呢?这是被别人问起的一个问题,好好学习了一下,进行总结如下:在bash中,可以用以下三种方式来处理命令行参数 ...

  7. CCF 201403-3 命令行选项 (STL模拟)

    问题描述 请你写一个命令行分析程序,用以分析给定的命 令行里包含哪些选项.每个命令行由若干个字符串组成,它们之间恰好由一个空格分隔.这些字符串中的第一个为该命令行工具的名字,由小写字母组成,你的程序 ...

  8. 命令行参数的处理函数getopt

    命令参数 在linux下, shell命令的参数分两种情况: a.参数需要附加信息, 如"wget http://www.abc.com/1.zip -o 1.zip" b.参数不 ...

  9. linux C语言getopt()函数的使用

    getopt被用来解析命令行选项参数. #include <unistd.h> 函数及参数介绍 extern char *optarg; //选项的参数指针,如果选项字符串里的字母后接着冒 ...

随机推荐

  1. 通读AFN③--HTTPS访问控制(AFSecurityPolicy),Reachability(AFNetworkReachabilityManager)

    这一篇主要介绍使用AFN如何访问HTTPS网站以及这些做法的实现原理,还有介绍AFN的网络状态监测部分AFNetworkReachabilityManager,这个模块会和苹果官方推荐的Reachab ...

  2. 【代码笔记】iOS-文字走马灯效果

    一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController ...

  3. CentOS7— Redis安装(转和延续)

    Part I. Redis安装(转载部分) 一.安装 wget http://download.redis.io/redis-stable.tar.gz tar xvzf redis-stable.t ...

  4. localForage——轻松实现 Web 离线存储

    Web 应用程序有离线功能,如保存大量数据集和二进制文件.你甚至可以做缓存 MP3 文件这样的事情.浏览器技术可以保存离线数据和大量的储存.但问题是,如何选择合适技术,如何方便灵活的实现. 如果你需要 ...

  5. 浏览器内核与js引擎

    摘要: 面试一个大公司的时候问到了一个问题,让我谈谈主要的浏览器内核以及他们的特点,当时并没有详细的回答,回来之后自己在网上找了找资料,总结了下分享给大家. 简介: 在维基百科上是这样介绍浏览器内核的 ...

  6. QR二维码生成器源码(中间可插入小图片)

    二维码终于火了,现在大街小巷大小商品广告上的二维码标签都随处可见,而且大都不是简单的纯二维码,而是中间有个性图标的二维码. 我之前做了一个使用google开源项目zxing实现二维码.一维码编码解码的 ...

  7. 获取Android状态栏高度的屡试不爽的方法

    文本转载于:http://blog.csdn.net/yinkai1205/article/details/8638864 如下代码所示: [java] view plaincopy private  ...

  8. solrj-solr Guide 4.7

    solrj是一个很容易使java应用程序和solr进行交互的一个API,solrj隐藏了很多连接Solr的细节,允许你的应用程序使用简单的高级方法和solr互动交流. solrj的核心就是 org.a ...

  9. LabVIEW中的UDP通信

    UDP(user datagram protoco1)提供向接收端发送信息的最简便的协议,与TCP不同,UDP不是面向连接的可靠数据流传输协议,而是面向操作的不可靠数据流传输协议.UDP在数据传输之前 ...

  10. How to check a not defined variable in javascript

    javascript里怎么检查一个未定义的变量? in JavaScript null is an object. There's another value for things that don' ...