平时写程序时,有时需要对命令行参数进行处理。在接触本文所涉及的内容前,我们可能想到的方法是顺序提取命令行参数,进行顺序判断处理;然而,这种方法相当不灵活,尤其是在遇到带有可选参数的情况时,很难处理。为此,Linux提供了如下接口进行命令行参数的处理:
#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);
我们首先介绍几个全局变量
optarg; //指向当前选项参数(如果有)的指针
optind, //再次调用 getopt() 时的下一个 argv 指针的索引
opterr, //指定getopt、getopt_long、getopt_long_only是否在遇到错误时将错误输出到标准输出流
optopt; //最后一个未知选项
getopt
int getopt(int argc, char * const argv[],const char *optstring);
argc和argv与main函数的两个参数相匹配的
optstring是一个字符串,形式如“a:b::cd:”,分别表示选项 程序支持的命令行选项有-a、-b、-c、-d,冒号含义如下:
- 只有一个字符,不带冒号——只表示选项, 如-c
- 一个字符,后接一个冒号——表示选项后面带一个参数,如-a 100
- 一个字符,后接两个冒号——表示选项后面带一个可选参数,即参数可有可无,如果带参数,则选项与参数直接不能有空格,形式应该如-b200
下面看一个例子:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int opt;
char *optstring = "a:b::cd:";
while ((opt = getopt(argc, argv, optstring)) != -1)
{
printf("opt = %c\n", opt);<span style="white-space:pre"> </span> //输出选项名称
printf("optarg = %s\n", optarg); //输出选项后接的参数
printf("optind = %d\n", optind); //输出当前命令行参数下一个参数的下标
printf("argv[optind-1] = %s\n\n", argv[optind-1]); //
}
return 0;
}
测试
windeal@ubuntu:Test$ ./a.out -a 100 -b200 -b -c -d 300
opt = a
optarg = 100
optind = 3
argv[optind-1] = 100
opt = b
optarg = 200
optind = 4
argv[optind-1] = -b200
opt = b
optarg = (null)
optind = 5
argv[optind-1] = -b
opt = c
optarg = (null)
optind = 6
argv[optind-1] = -c
opt = d
optarg = 300
optind = 8
argv[optind-1] = 300
windeal@ubuntu:Test$
getopt_long
getopt_long相当于getopt的拓展,getopt_long支持长选项参数(即选项不是单个字符)。
getopt_long其原型如下:
int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
除了与getopt相同的三个参数外,getopt_long还带有参数longopts,和longindex。
longindex表示当前长参数在longopts中的索引值
longopts类型定义如下
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
no_argument(或者是0)时 ——参数后面不跟参数值
required_argument(或者是1)时 ——参数输入格式为:--参数 值 或者 --参数=值。
optional_argument(或者是2)时 ——参数输入格式只能为:--参数=值。
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#define VAL1 0
#define VAL2 1
#define VAL3 2
int main(int argc, char* argv[])
{
int opt;
int this_option_optind = optind ? optind : 1;
char *optstring = "a:b::cd:";
struct option long_options[] = {
{"lopt1", no_argument, 0, VAL1},
{"lopt2", required_argument, 0, VAL2},
{"lopt3", optional_argument, 0, VAL3},
{"lopt4", no_argument, 0, VAL1},
{0,0,0,0}
};
int option_index = 0;
while ((opt = getopt_long(argc, argv, optstring, long_options, &option_index)) != -1)
{
switch(opt)
{
case VAL1:
case VAL2:
case VAL3:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
case 'a':
case 'b':
case 'c':
case 'd':
printf("opt = %c\n", opt); //输出选项名称
printf("optarg = %s\n", optarg); //输出选项后接的参数
printf("optind = %d\n", optind); //输出当前命令行参数下一个参数的下标
printf("argv[optind-1] = %s\n\n", argv[optind-1]); //
default:
exit(-1);
break;
}
}
return 0;
}
测试结果:
windeal@ubuntu:Test$ ./a.out --lopt1 --lopt2 23 --lopt3=33 --lopt4 -a 100
option lopt1
option lopt2 with arg 23
option lopt3 with arg 33
option lopt4
opt = a
optarg = 100
optind = 8
argv[optind-1] = 100
windeal@ubuntu:Test$ vim test.c
getopt_long_only
getopt_long_only与getopt_long参数表和功能基本相同,主要差别的地方在于长选项参数的解析。
在getopt_long中,长选项参数需要由双横杠开始,即--name, 而-name会被解析成-n,-a,-m和-e在optstring中匹配
在getopt_long_only中,--name和-name都被解析成长选项参数。