红联Linux门户
Linux帮助

linux命令行参数解析函数getopt

发布时间:2017-01-03 10:23:05来源:linux网站作者:jiedou1991
在学习开源代码过程中,经常遇到命令行解析函数 getopt,网上查阅了一些资料,总结一下。
 
说到命令行解析,最简单的方式就是利用C语言main函数的两个参数argc和argv来实现,当 C 运行时库程序启动代码调用 main() 时,会将命令行的参数传过来,参数个数放在argc中,参数内容放在argv中,命令行上除命令名之外的字符串。参数由多项构成,项与项之间用空白符彼此隔开。
 
//argc.c
#include <stdio.h>  
int main(int argc,char *argv[])  
{  
int i;  
for (i=0;i<argc;++i)  
printf("%s ",argv[i]);  
return 0;  
}
 
输入
#gcc argc.c 
#./a.out  er ertrytuyu uiu -dfd gh  
输出
#./a.out  er ertrytuyu uiu -dfd gh
 
实际中程序的命令行参数比较复杂,用上述方法解析起来非常麻烦,为了简化对于命令行参数的解析,一些专家开发了getopt()函数,同时提供了几个外部变量,简化了命令行参数的解析。命令行参数可进一步分为选项和操作数,选项通常以'-'开头,选项后跟的就是操作数。例如 cat -n getopt.txt ,n是选项getopt.txt是操作数,还有以下约定:
a.选项名是单字符,且以短横‘-‘为前綴;
b.多个具有操作数的选项不能合并;其余的选项会被解析成第一个选项的操作数
c.多个不需要操作数的选项可以合并;如 ls -l -t -a = ls -lta
 
#include <unistd.h>
int getopt(int argc, char * const argv[], const char *optstring);
argc与argv跟main函数中argc和argv意义相同
optstring是一个包含合法选项字符的字符串,字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。单个字符后跟两个冒号,表示该选项后可以跟一个参数,不能用空格隔开,中间有空格相当于不带参数。
extern char *optarg;  //指向选项的操作数
extern int optind,   //下一个选项的索引(在argv中的索引)
extern int opterr,  //当opterr=0时,getopt不向stderr输出错误信息。
extern int optopt;  //当命令行选项字符不包括在optstring中或者选项缺少必要的参数时,该选项存储在optopt中,同时getopt返回'?'
 
下面详细讲下getopt()解析命令行参数的基本过程:以optstring="ab:c:de::" 为例
0          1       2       3      4      5       6      7      8       9
$ ./a.out     f1     -a      -b     -c     f2      -d     f3     -e      f4
由optstring可知:选项a,d没有参数,b,c有一个参数,选项e可以有一个参数且必须紧跟在选项后不能以空格隔开。   扫描过程中,optind是下一个选项的索引, 非选项参数将跳过,同时optind增1。optind初始值为1。当扫描argv[1]时,为非选项参数,跳过,optind=2;扫描到-a选项时, 下一个将要扫描的选项是-b,则optind更改为3;扫描到-b选项时,因为b必须有操作数,则会将-c解析成选项b的参数),optind=5,扫描到f2为非选项跳过,optind=6;扫描到-d选项,后面没有参数,optind=7;扫描到f3为非选项跳过,optind=8;扫描到-e后面本来应该有参数,但是有空格认为e的参数为空。optind=9,解析完成后,getopt会将argv数组修改成下面的形式:
0          1       2       3      4      5       6      7      8       9
$ ./a.out      -a      -b      -c     -d     -e      f1     f2     f3      f4
解析完成后,optind会指向非选项的第一个参数,如上面,optind将会指向f1。
 
下面关门放代码:
//getopt1.c     
#include <stdio.h>  
#include <unistd.h>  
int main(int argc,char *argv[])  
{  
int ch;  
int i;  
while((ch=getopt(argc,argv,"a:b::cde"))!=-1)  
{  
printf("optind:%d\n",optind);  
printf("optarg:%s\n",optarg);  
printf("ch:%c\n",ch);  
printf("optopt+%c\n",optopt);  
}  
printf("%d\n",optind);  
for (i=0;i<argc;++i)  
printf("%s ",argv[i]);  
}
 
输入
#gcc getopt1.c 
#./a.out f1 f2 f3  -a123 -b456 -cde  
输出
optind:5             //跳过非选项参数  f1 f2 f3 解析-a123 指向下一个要解析的-b456
optarg:123        //本次选项的操作数
ch:a                  //本次选项
optopt+            //因为解析没出错,所以optopt为空
optind:6
optarg:456
ch:b
optopt+
optind:6
optarg:(null)
ch:c
optopt+
optind:6
optarg:(null)
ch:d
optopt+
optind:7             //虽然这里仍然会加1,尽管索引7已经超过argv的范围
optarg:(null)
ch:e
optopt+
4
./a.out -a123 -b456 -cde f1 f2 f3  //这是解析过后的argv,选项和操作数在左,其余参数在右
 
上面是解析过程没出错时的情况,下面介绍异常情况
a.无效的选项
输入
#./a.out -c1    
输出
optind:1                                //getopt认为1是下一个要解析的选项 所以 optind=1
optarg:(null)
ch:c
optopt+                                //以上为-c的解析
./a.out: invalid option -- '1'    //这里解析出错 1不是合法的选项,是在执行getopt函数时报错
optind:2         
optarg:(null)
ch:?                                     //出错getopt返回 ?
optopt+1                             //optopt存储出错选项1
2                                         //这是解析完后的optind的值                                        
./a.out -c1                          //这是解析过后的argv
b.第二种出错情况,没有选项传参
输入
#./a.out -a
输出
./a.out: option requires an argument -- 'a'
optind:2 
optarg:(null)
ch:?
optopt+a
2
./a.out -a
 
补充:
在调用getopt()之前,将opterr设置为0,这样可以阻止getopt()函数输出错误消息。如果optstring参数的第一个字符是冒号,那么getopt()函数就会根据错误情况返回不同字符,“无效选项”getopt()会返回'?',并且optopt包含了无效选项字符(这是正常的行为)。“缺少选项操作数”getopt()会返回':',如果optstring的第一个字符不是冒号,那么只要出错getopt()返回'?'。
 
总结:这两天被这个getopt搞得晕头转向,主要还是不了解它解析命令行参数的过程,除了getopt,getopt_long,getopt_long_only函数也可以解析命令行参数,有时间再研究。
 
本文永久更新地址:http://www.linuxdiyf.com/linux/27478.html