语言下解析命令行选项参数的函数---getopt
。
通常我们的命令行选项有两种存在:长选项
和短选项
。长选项
使用--
标识,而短选项使用-
标识。
函数原型及其相关常量说明
头文件
#include <unistd.h>
原型
int getopt(int argc, char * const argv[], const char *optstring);
常量
extern char *optarg; //选项的参数指针
extern int optind; //扫描选项时,标识下一个选项的index;全部扫描结束之后,标识第一个非选项参数的index。
extern int opterr; //出现不可识别的选项时,将打印错误信息;将opterr赋值为0,则不打印错误信息。
extern int optopt; //当命令行选项字符不存在或者缺少必要的参数时,将该选项存在optopt中,同时getopt函数返回`?`。
getopt传入参数说明
- argc
由main函数传入,参数个数。 - argv
由main函数传入,参数数组 - optstring
选项字符集合,形如:a:bc:d
这种。
optstring
说明
若选项后带参数,需在选项后加:
,对应的参数值保存在optarg
中。
如ab:
,指明应用程序支持-a
和-b
两个选项,其中-a
不带参数,而-b
带参数。
./test -a -b param
总结如下:
1.单个字符,表示选项,
2.单个字符后接一个冒号:
表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。
3 单个字符后跟两个冒号::
,表示该选项后必须跟一个参数。参数必须紧跟在选项后不能以空格隔开(如:-efilename,-e为选项,filename为参数)。该参数的指针赋给optarg。(这个特性是GNU的扩展)。
扫描解析过程
即,getopt函数如何对选项及参数进行解析的过程。
getopt首先扫描argv[1]到argv[argc-1],并将选项及参数依次放到argv数组的最左边,非选项参数依次放到argv的最后边。
比如,我们的optstring
为ab:c:de::
执行命令如下:
./test file1 -a -b -c code -d file2 -e file3
一共10个参数,对应如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
./test | file1 | -a | -b | -c | code | -d | file2 | -e | file3 |
在扫描过程中,optind
是下一个选项的索引值,非选项参数将被跳过,同时optind
增1。optind
初始值为1
。
当扫描argv[1]时,为非选项参数,跳过,optind=2;
扫描到-a选项时, 下一个将要扫描的选项是-b,则optind更改为3;
扫描到-b选项时,后面有参数(会认为-c为选项b的参数),optind=5;
扫描到code非选项跳过optind=6;
扫描到-d选项,后面没有参数,optind=7;
扫描到file2非选项跳过optind=8;
扫描到-e后面本来应该有参数,optind=9但是有空格所以e的参数为空。
扫描过程如上,待扫描结束之后,argv数组排列如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
./test | -a | -b | -c | -d | -e | file1 | code | file2 | file3 |
可以看到上述,选项字符都依次排列到了最左边,而非选项参数都排列到了最右边;同时optind会指向非选项的第一个参数,如上面,optind将指向file1。
如果修改参数排列顺序为:
./test -a -b -c code -d file2 -e file3 file1
扫描后的顺序为:
./test -a -b -c -d -e code file2 file3 file1
此时optind指向的参数为code
。
代码示例
代码如下:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
int aflag=0, bflag=0, cflag=0;
int ch;
int i;
printf("optind:%d,opterr:%d\n",optind,opterr);
printf("--------------------------\n");
while ((ch = getopt(argc, argv, "ab:c:de::")) != -1)
{
printf("optind: %d,argc:%d,argv[%d]:%s\n", optind,argc,optind,argv[optind]);
printf("argv:");
for(i=0; i<argc; i++){
printf("%s ", argv[i]);
}
printf("\n");
switch (ch) {
case 'a':
printf("HAVE option: -a\n\n");
break;
case 'b':
printf("HAVE option: -b\n");
printf("The argument of -b is %s\n\n", optarg);
break;
case 'c':
printf("HAVE option: -c\n");
printf("The argument of -c is %s\n\n", optarg);
break;
case 'd':
printf("HAVE option: -d\n");
break;
case 'e':
printf("HAVE option: -e\n");
printf("The argument of -e is %s\n\n", optarg);
break;
case '?':
printf("Unknown option: %c\n",(char)optopt);
break;
}
}
printf("----------------------------\n");
printf("argv:");
for(i=0; i<argc; i++){
printf("%s ", argv[i]);
}
printf("\n");
printf("optind=%d,argv[%d]=%s\n",optind,optind,argv[optind]);
}
执行结果如下:
参考: