getopt()函数用于命令行参数解析。先来看一下main函数的参数。
1,程序参数
C语言编写的linux程序运行时,是从main函数开始的。main函数的声明如下:
int main(int argc, char* argv[])
或者
int main(int argc, char** argv)
其中,argc是程序参数的个数,argv是一个代表自身的字符串数组。
实验:下面这个程序args.c对其参数进行检查:
<span style="font-size:12px;">#include<stdio.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
int arg;
printf("The number of parameters: argc=%d\n",argc);
for(arg=0;arg<argc;arg++)
{
printf("argv[%d] = %s\n",arg,argv[arg]);
}
exit(0);
}</span>
经过编译后,执行
gcc -o args args.c
./args -a -b host -chello -de -f world
结果如下:
The number of parameters: argc=8
argv[0] = ./args
argv[1] = -a
argv[2] = -b
argv[3] = host
argv[4] = -chello
argv[5] = -de
argv[6] = -f
argv[7] = world
注:1)参数个数包括程序名本身; 2)argv是一个字符串数组;3)-de选项其实是-d和-e选项组合的,getopt可以识别这种情况的两个选项。
2,getopt函数
#include <unistd.h>
int getopt(int argc, char * const argv[], const char *optstring);
以下全局变量配合 getopt 函数。
extern char *optarg;
extern int optind;
extern int optopt;
extern int opterr;
实际上,在命令行中,可以支持这样命令输入的信息:
选项:一个选项一般完成不同的功能的操作。
参数(关联值):在执行相应选项功能操作时输入的信息。
-a:选项:表示所有。
-h host_id: h 就是一个选项,但host_id 实际上是一个IP,也就是h 的参数。
getopt函数将传递给main函数的argc和argv作为参数,同时接受一个选项指定符字符串optstring,该字符告诉getopt哪些选项可用,以及它们是否有关联值(参数)。optstring约定:
(1)如果就是一个字符,表示某个选项。
(2)如果一个字符后有1 个冒号,表示选项后面一定要跟一个参数。参数可以紧跟选项或者与选项相隔一个空格。
(3)如果一个字符后有2 个冒号,表示选项后面可有有一个参数,也可以没有参数,在选项后的参数一定不能跟它以空格间隔。
例如getopt 函数第三个参数为以下值:
“ab:c::d::”
a 后面 没有冒号,是一个选项。
b 后面有冒号,其后的内容一定要有理解为参数。
c 和d 双冒号,其后的内容可以有,也可以没有,但如果有,则这个参数一定坚挨着。
因此如下:
./getopt –a –b host –chello –d
getopt每次先查找‘-’后面的字符,再查看该字符是否是optstring中的选项,以及是否带有正确的参数。对于前面不带‘-’的,且不是作为参数的字符或字符串,则不予理会。
具体getopt 怎么来解释我们的选项和参数。
每成功执行一次,将返回当前的一个选项。循环调用getopt就可以依次得到每个选项。
(1)如果选项有一个关联值,则extern char *optarg指向这个值,否则为NULL;
(2)如果选项处理完毕,getopt返回-1;
(3)如果遇到一个无法识别的选项,getopt返回一个问号(?),并把它保存到外部变量optopt中;并把有一个关联值,则extern char *optarg指向这个值,否则为NULL;
(4)如果一个选项要求有一个关联值(例如例子中的-a),但用户未提供这个值,getopt通常将返回一个问号;但如果
./getopt_exp -a -b 'hi there' -chello world -de -f (optstring为"a:b:c::de")
程序会将-b当成-a的关联值。
如果我们将选项字符串的第一个字符设置为冒号,那么getopt将在用户未提供值的情况下返回冒号,而不是?。
extern char *optarg; //如果当前选项后面一定要跟一个参数,且存在参数,则optarg指向该参数;否则为null
extern int optind; //下一个要处理参数的索引
extern int optopt; //用于存储无法识别的选项
extern int opterr; //opterr== 0,不将错误输出的标准错误输出设备。
<span style="font-size:12px;">#include<stdio.h>
#include<unistd.h>
int main(int argc, char* argv[])
{
int opt,i;
opterr=0;
while((opt=getopt(argc,argv,"a:b:c::de"))!=-1)
{
switch(opt)
{
case 'a':
printf("option=a,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
break;
case 'b':
printf("option=b,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
break;
case 'c':
printf("option=c,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
break;
case 'd':
printf("option=d,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
break;
case 'e':
printf("option=e,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
break;
case '?':
printf("opt=?,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
break;
default:
printf("default,opt=%c,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",opt,optarg,optind,optopt,opterr);
break;
}
printf("opt=%c\n",opt);
printf("argv[%d]=%s\n",optind,argv[optind]);
}
printf("\nopt=%d,optind=%d\n\n",opt,optind);
for(;optind<argc;optind++)
printf("argv[%d]= %s\n",optind,argv[optind]);
printf("\n");
for(i=1;i<argc;i++)
printf("at the end ---- argv[%d]=%s\n",i,argv[i]);
return 0;
}</span>
编译:gcc -o getopt_exp getopt_exp.c;执行./getopt_exp -a here -b 'hi there' -chello -de come -f world后,结果为
option=a,optarg=here,optind=3,optopt=,opterr=0
opt=a
argv[3]=-b
option=b,optarg=hi there,optind=5,optopt=,opterr=0
opt=b
argv[5]=-chello
option=c,optarg=hello,optind=6,optopt=,opterr=0
opt=c
argv[6]=-de
option=d,optarg=(null),optind=6,optopt=,opterr=0
opt=d
argv[6]=-de
option=e,optarg=(null),optind=7,optopt=,opterr=0
opt=e
argv[7]=come
opt=?,optarg=(null),optind=9,optopt=f,opterr=0
opt=?
argv[9]=world
opt=-1,optind=8
argv[8]= come
argv[9]= world
at the end ---- argv[1]=-a
at the end ---- argv[2]=here
at the end ---- argv[3]=-b
at the end ---- argv[4]=hi there
at the end ---- argv[5]=-chello
at the end ---- argv[6]=-de
at the end ---- argv[7]=-f
at the end ---- argv[8]=come
at the end ---- argv[9]=world
注:1)getopt能够处理出现在程序参数中任意位置的选项。程序结束后,getopt实际上重组了argv数组,把所有非选项参数集中在一起,从argv[optind]位置开始。如程序结果中的argv[8]。
for(;optind<argc;optind++)
printf("argv[%d]= %s\n",optind,argv[optind]);
2)opt,即 getopt函数的返回值,是一个选项,即一个字符,输出时用%c,不能用%s,否则会出现Segmentation fault (core dumped)的错误。