命令选项参数解析
我们都是知道程序在启动时是可以接收命令参数的。通过main(int argc,char **argv)
函数的argc和argv来传入命令参数。这时我们需要解析。当然glibc库中包含了相关函数来方便我们解析命令参数。
为了表述方便,我们用命令gcc -o exefile test.c
来举例说明。其中gcc是运行命令(可执行文件),-o exefile test.c
是它的参数。各个参数之间使用空格分开。main()
函数的argc
表明了输入参数的个数。此例的argc=4
(gcc本身也算一个参数)。argv
为一个字符串指针数组。存放这所有输入参数的指针。如argv[0]
指向gcc
,argv[1]
指向-o
,argv[2]
指向exefile
等等。
除此之外,输入参数中有些术语需要了解。如下
短选项
:如上面的-o
就是短选项。它由-
开头,后面只能跟一个字符。短选项
又具体分为:- 必须带参数的短选项:指它后面必须要有一个参数。如
-o exefile
,exefile就是它的参数。 - 可选带参的短选项:指它后面可以带或不带参数。
- 不带参的短选项:指它后面不带参数。
- 必须带参数的短选项:指它后面必须要有一个参数。如
长选项
:如--version
就是长选项。它由--
开头,后面可跟多个字符。它也分必须带参
,可选带参
,不带参
。无选项参数
:它前面不需要有短选项
或长选项
。如上面的test.c
参数。
glibc库中提供了支持解析短选项的getopt()
函数和长选项的getopt_long()
函数。看下面的介绍和使用例程。
解析程序输入参数相关函数介绍
下面函数都需要包括getopt.h
文件。
int getopt(int argc, char *const argv[],const char *optstring)
- 描述:解析命令行参数。调用
getopt()
函数解析完argv
数组后,会对其排序。将其无选项参数放在最后。如果不想让其排序,定义环境变量_POSIX_OPTION_ORDER
即可。 - argc,argv:和main函数的这两个参数一样。第一个代表参数个数。第二个是选项数组。
- optstring:指定选项格式。具体格式如下(
a
代表某个选项)a
:表示此选项没有参数,如-a
。如果跟了参数会报错。如-a lkd
这种格式错误。a:
:表示此选项有参数,如-a lkd
。以可连写为-alkd
。如果不跟参数会报错。a::
表示此选项的参数可选。当有时必须用连写方式-alkd
。此种格式是GNU扩展的。- eg:
optstring = "a:bc::"
表示a选项必须要有参数,b选项无参数,c选项可有可无。所以输入参数的格式应为./test -a lkd -b -cname
.
- return:如果选项成功找到,返回选项字母;当没有更多的选项参数可用时,它返回-1.
- 注意:对其无选项参数,可以在
getopt()
将选项参数解析完之后(此时会参数默认会自动排序,将其无选项参数放在了最后),直接使用optind
跟argc
对比打印。
for(int i = optind; i < argc; i++){ printf("argv[%d]:%s\n",i,argv[i]); }
- 描述:解析命令行参数。调用
char *optarg
全局变量- 描述:
getopt()
会设置此变量。使其指向选项参数的值字符串。
- 描述:
int optind
全局变量- 描述:argv数组中下一个要解析元素的索引(inxdex)。系统初始化时此值为1.调用者可以在使用过程中将它复位到1.
int optopt
全局变量- 描述:当
getopt()
遇到未知的选项字符或缺少必需参数的选项时,它将该选项字符存储在该变量中。您可以使用它来提供您自己的诊断消息。
- 描述:当
int opterr
全局变量- 描述:当如果设置
opterr!=0
,那么当getopt()
遇到一个未知的选项字符或一个缺少必需参数的选项时,将向标准错误流输出一条错误消息.这是默认的行为。如果设置opterr=0
,getopt()
不会打印任何消息,但它仍然返回字符?
表示错误。
- 描述:当如果设置
使用例程。命令行运行命令为./test xxx -a guo -b wei -c ddd
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int c;
/* 打印原始的输入参数 */
printf("argc:%d\n",argc);
for(int i = 0; i < argc; i++){
printf("argv[%d]:%s\n",i,argv[i]);
}
/* 解析选项参数并打印 */
printf("------------------\n");
while( (c = getopt(argc,argv,"a:b:c")) != -1){
char *parg = (optarg == NULL ? "NULL" : optarg);
printf("argv[%d]:-%c %s\n",optind-1,c,parg);
}
/* 打印无选项参数 */
printf("------------------\n");
for(int i = optind; i < argc; i++){
printf("argv[%d]:%s\n",i,argv[i]);
}
/* 打印排序后的参数 */
printf("------------------\n");
printf("argc:%d\n",argc);
for(int i = 0; i < argc; i++){
printf("argv[%d]:%s\n",i,argv[i]);
}
}
下面的这两个函数是GNU扩展的。用于支持长选项的解析。
int getopt_long(int argc, char * const argv[],const char *optstring,const struct option *longopts, int *longindex)
- 描述:在
getopt()
函数的基础上怎加了长选项(如--version
)的解析支持。如果程序只支持长选项,应让optstring=""
。 - longopts选项应该是一个
struct option
结构体数组指针。最后一个元素的所有成员要为0.此结构体如下:
struct option { const char *name; //长选项名称。 int has_arg; //有三种情况。no_argument:表明此选项不需要参数。required_argument表示必须要有参数。optional_argument表示参数可选。 int *flag; //如果flag=NULL.那么函数返回val.否则返回0.*flag里保存val. int val;函数返回或者*flag的值。 };
- 再解释一下结构体中的flag和val.它俩是配合使用的。主要功能就是匹配短选项。比如某个命令的长选项
--version
和短选项-V
的含义一样。那么就可以使val = V,flag=NULL
那么getopt_long()的返回值就为短选项。处理方式变得和getopt()一模一样。 - longindex:它指向一个变量,该变量被设置为长选项相对于longopts的索引。
- 描述:在
getopt_long_only()
.- 描述:功能类似
getopt_long()
.只是 getopt_long 只将–name当作长参数,但 getopt_long_only 会将–name和-name两种选项都当作长参数来匹配。getopt_long_only如果选项-name不能在longopts中匹配,但能匹配一个短选项,它就会解析为短选项。
- 描述:功能类似
下面是一个使用例程:
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int longindex;
struct option longopts[] = {
{"version",no_argument,0,'V'},
{0,0,0,0}
};
while(1){
int c = getopt_long(argc,argv,"a:b:c",longopts, &longindex);
if(c == -1){
break;
}
char *parg = (optarg == NULL ? "NULL" : optarg);
printf("-%c %s\n",c,parg);
}
}