一、linux应用程序如何接收参数?
1、argc、argv
Linux应用程序执行时,我们往往通过命令行带入参数给程序,比如:
ls/dev/-l
其中参数 /dev/、**-l**都是作为参数传递给命令ls
应用程序又是如何接收这些参数的?
通常应用程序都是从main函数开始执行,传统的main函数风格如下:
intmain(intargc,char*argv[])
argc:
程序的命令行参数的数量,用于统计参数数量。
argv:
是一个指向一个字符串数组的指针,数组包含了参数,每个字符串就是一个参数,最后一个元素为0。
过一般习惯使用多级指针来操作字符串。
*charargv[]有时候我们也写成charargv,
**argv[]**是一个存放字符类型元素地址的数组。
因为 C 中是有字符串的概念的:将每个字符存放在 char 数组,最后一个元素为****表示字符串的结束。
**printf(%s)**就是输出字符串。
并且一般使用argv指针来访问、处理argv[]数组的内容。
C语言中,数组就是一个指针加偏移量。
所以argv则是指向一个指针数组argv[]的指针,不用定义,直接可以用。
在argv[]数组中存放的的指针指向输入命令的各部分(调用程序、选项、参数)。
2、举例
下面我们用一个实例来理解argc和argv
/*
*argc:命令行参数的个数
*argv:字符指针数组(指向各个命令行参数的字符指针所构成的数组)
*/
intmain(intargc,char*argv[])//接收命令行参数
{
printf("argc=%d
",argc);
for(inti=0;i< argc; i++) {
printf("argv[%d]:%s
",i,argv[i]);//遍历字符指针数组argv
}
return0;
}
执行结果:
peng@ubuntu:~/work$./peng arg1 arg2 arg3
argc=4
argv[0]:./peng
argv[1]:arg1
argv[2]:arg2
argv[3]:arg3
参数与argc,argv关系如下:二、选项
1、选项含义
linux程序除了上述情况以外,我们还经常会遇到一个使用方法就是选项应用,
比如:ping命令
peng@ubuntu:~/work$ping-h
Usage:ping[-aAbBdDfhLnOqrRUvV][-c count][-i interval][-I interface]
[-m mark][-M pmtudisc_option][-l preload][-p pattern][-Q tos]
[-s packetsize][-S sndbuf][-t ttl][-T timestamp_option]
[-w deadline][-W timeout][hop1...]destination
参数含义:
-a:尝试将IP地址解析为主机名。
-A:使用响应数据包中的附加数据。
-b:允许ping广播地址。
-B:不允许ping广播地址。
-c count:设置要发送的数据包数量。
-d:使用SO_DEBUG选项。
-D:不将socket设为分离模式。
-f:向目标发送一个“强制”数据包。
-h:显示帮助信息。
-i interval:设置发送数据包之间的时间间隔。
-I interface:设置要使用的网络接口。
-l preload:设置发送的数据包数量。
-m mark:设置ping数据包的标记。
-M pmtudisc_option:设置MTU发现选项。
-n:不要将IP地址解析为主机名。
-O:启用原始输出。
-p pattern:设置数据包的模式。
-Q tos:设置服务类型。
-r:不使用路由表,直接发送数据包到目标主机。
-R:启用记录路由。
-s packetsize:设置数据包的大小。
-S sndbuf:设置套接字的发送缓冲区大小。
-t ttl:设置数据包的TTL值。
-T timestamp_option:设置时间戳选项。
-U:使用UDP数据包。
-v:显示详细的ping命令输出。
-V:显示ping命令的版本信息。
-w deadline:设置等待响应的时间。
-W timeout:设置等待响应的超时时间。
destination:指定要ping的目标主机或IP地址。
这些-开头的都是选项, []表示可选的意思
[-aAbBdDfhLnOqrRUvV]是无参的选项
[-c count][-i interval][-I interface]
[-m mark][-M pmtudisc_option][-l preload][-p pattern][-Q tos]
[-s packetsize][-S sndbuf][-t ttl][-T timestamp_option]
[-w deadline][-W timeout][hop1...]这些都是有参数的选项
destination必须填写的参数
前辈们利用这点发明了“UNIX 风格”的命令,选项前面加一个横杠-,用于区分选项和参数。
2、程序如何区分参数和选项?
在程序的代码实现中,按照 UNIX 的代码惯例,上来直接跳过第一个,然后判断指针指向的字符串第一个字符是不是-,如果是的,那么进入一个switch判断,用case列出多种支持的情况下,应该执行什么代码。
例如下面这样就可以判断选项和处理参数:
intc;
while(--argc>0&&(*++argv)[0]=='-'{
while(c=*++argv[0]{
switch(c){
case'x':
...
break;
case'n':
...
break;
default:
printf("xxx:illegal opyion%c
",c);
...
break;
}
}
}
3、getopt、getopt_long
事实这么处理选项参数是比较麻烦的,
linux提供了选项解析的函数:
//头文件
#include
#include/*所在头文件*/
intgetopt(intargc,char*constargv[],constchar*optstring);
intgetopt_long(intargc,char*constargv[],constchar*optstring,
conststruct option*longopts,int*longindex);
intgetopt_long_only(intargc,char*constargv[],constchar*optstring,
conststruct option*longopts,int*longindex);
externchar*optarg;/*系统声明的全局变量*/
externintoptind,opterr,optopt;
三、getopt
1、定义
intgetopt(intargc,char*constargv[],constchar*optstring);
功能:
getopt是用来解析命令行选项参数的,但是只能解析短选项:**-d100**,不能解析长选项:**--prefix**
参数
argc:
main()函数传递过来的参数的个数
argv:
main()函数传递过来的参数的字符串指针数组
optstring:
选项字符串,告知getopt()可以处理哪个选项以及哪个选项需要参数
返回:
如果选项成功找到,返回选项字母;如果所有命令行选项都解析完毕,返回-1;
如果遇到选项字符不在 optstring 中,返回字符‘?’;
如果遇到丢失参数,那么返回值依赖于optstring中第一个字符,
如果第一个字符是‘:’则返回’:‘,否则返回’?'并提示出错误信息。
2、optstring 含义 【重要】
下边重点举例说明optstring的格式意义:
char*optstring=“ab:”;
单个字符a 表示选项a没有参数格式:-a即可,不加参数
单字符加冒号b:表示选项b有且必须加参数格式:-b 100或-b100,但-b=100错
单字符加2冒号c::表示选项c可以有,也可以无格式:-c200,其它格式错误
上面这个 optstring 在传入之后,getopt 函数将依次检查命令行是否指定了 -a, -b, -c(这需要多次调用 getopt 函数,直到其返回-1),当检查到上面某一个参数被指定时,函数会返回被指定的参数名称(即该字母)
系统声明的4个全局变量含义如下:
optarg ——指向当前选项参数(如果有)的指针。
optind ——再次调用 getopt()时的下一个 argv指针的索引。
optopt ——最后一个未知选项。
opterr——如果不希望getopt()打印出错信息,则只要将全域变量opterr设为0即可。
3、实例
说千道万,不如来一个实例:
#include
#include
#include
intmain(intargc,char*argv[])
{
intopt;
char*string="a:c:d";
while((opt=getopt(argc,argv,string))!=-1)
{
printf("opt=%c ",opt);
printf("optarg=%s ",optarg);
printf("optind=%d ",optind);
printf("argv[optind]=%s
",argv[optind]);
}
}
-
正确输入参数,执行结果如下:
peng@ubuntu:~/work/test$./peng-a100-b 200-c 300-d
opt=aoptarg=100optind=2argv[optind]=-b
opt=boptarg=200optind=4argv[optind]=-c
opt=coptarg=300optind=6argv[optind]=-d
opt=doptarg=(null)optind=7argv[optind]=(null)
或者
ork/test$./peng-a100-b200-c300-d
opt=aoptarg=100optind=2argv[optind]=-b200
opt=boptarg=200optind=3argv[optind]=-c300
opt=coptarg=300optind=4argv[optind]=-d
opt=doptarg=(null)optind=5argv[optind]=(null)
-
输入选项参数错误的情况
peng@ubuntu:~/work/test$./peng-a 100-b 200-c 300-d
opt=aoptarg=(null)optind=2argv[optind]=100
opt=boptarg=200optind=5argv[optind]=-c
opt=coptarg=300optind=7argv[optind]=-d
opt=doptarg=(null)optind=8argv[optind]=(null)
导致解析错误,第一个 optarg = null,实际输入参数 100,由于格式不正确造成的(可选参数格式固定)
- 参数丢失,也会导致错误
peng@ubuntu:~/work/test$./peng-a-b 200-c
opt=aoptarg=(null)optind=2argv[optind]=-b
opt=boptarg=200optind=4argv[optind]=-c
./peng:option requires an argument--'c'
opt=?optarg=(null)optind=5argv[optind]=(null)
c选项是必须有参数的
- 命令行选项未定义,-e选项未在optstring中定义,会报错:
peng@ubuntu:~/work/test$./peng-t
./peng:invalid option--'t'
opt=?optarg=(null)optind=2argv[optind]=(null)
四、getopt_long
1、定义
intgetopt_long(intargc,char*constargv[],constchar*optstring,
conststruct option*longopts,int*longindex);
功能:
包含 getopt 功能,增加了解析长选项的功能如:--prefix --help
参数:
longopts
指明了长参数的名称和属性
longindex
如果longindex非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值
返回:
对于短选项,返回值同 getopt 函数;
对于长选项,
如果flag是NULL,返回val,否则返回0;
对于错误情况返回值同getopt函数
2、struct option
structoption{
constchar*name;/*参数名称*/
inthas_arg;/*指明是否带有参数*/
int*flag;/*flag=NULL时,返回value;不为空时,*flag=val,返回0*/
intval;/*用于指定函数找到选项的返回值或flag非空时指定*flag的值*/
};
参数has_arg 说明:has_arg 指明是否带参数值,其数值可选:
no_argument
表明长选项不带参数,如:–name, --help
required_argument
表明长选项必须带参数,如:–prefix /root或--prefix=/root
optional_argument
表明长选项的参数是可选的,如:–help或–prefix=/root,其它都是错误
3、实例
#include
#include
#include
intmain(intargc,char*argv[])
{
intopt;
intdigit_optind=0;
intoption_index=0;
char*string="a:c:d";
staticstructoptionlong_options[]=
{
{"reqarg",required_argument,NULL,'r'},
{"optarg",optional_argument,NULL,'o'},
{"noarg",no_argument,NULL,'n'},
{NULL,0,NULL,0},
};
while((opt=getopt_long_only(argc,argv,string,long_options,&option_index))!=-1)
{
printf("opt=%c ",opt);
printf("optarg=%s ",optarg);
printf("optind=%d ",optind);
printf("argv[optind]=%s ",argv[optind]);
printf("option_index=%d
",option_index);
}
}
-
正确执行命令
peng@ubuntu:~/work/test$./long--reqarg 100--optarg=200--noarg
opt=roptarg=100optind=3argv[optind]=--optarg=200option_index=0
opt=ooptarg=200optind=4argv[optind]=--noargoption_index=1
opt=noptarg=(null)optind=5argv[optind]=(null)option_index=2
或者
peng@ubuntu:~/work/test$./long–reqarg=100--optarg=200--noarg
opt=ooptarg=200optind=3argv[optind]=--noargoption_index=1
opt=noptarg=(null)optind=4argv[optind]=(null)option_index=2
-
可选选项可以不给参数
peng@ubuntu:~/work/test$./long--reqarg 100--optarg--noarg
opt=roptarg=100optind=3argv[optind]=--optargoption_index=0
opt=ooptarg=(null)optind=4argv[optind]=--noargoption_index=1
opt=noptarg=(null)optind=5argv[optind]=(null)option_index=2
-
输入长选项错误的情况
peng@ubuntu:~/work/test$./long--reqarg 100--optarg 200--noarg
opt=roptarg=100optind=3argv[optind]=--optargoption_index=0
opt=ooptarg=(null)optind=4argv[optind]=200option_index=1
opt=noptarg=(null)optind=6argv[optind]=(null)option_index=2
五、getopt_long_only
getopt_long_only 函数与 getopt_long 函数使用相同的参数表,在功能上基本一致
只是 getopt_long 只将 --name 当作长参数,但 getopt_long_only 会将 --name 和 -name 两种选项都当作长参数来匹配
getopt_long_only 如果选项 -name 不能在 longopts 中匹配,但能匹配一个短选项,它就会解析为短选项。
六、综合实例
下面这个例子,是从开源项目ifplug提取出来的命令提取小例子,大家可以根据自己需要,基于这个框架,定制自己的程序。
#define_GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#defineETHCHECKD_VERSION"1.1"
intdelay_up=0;
char*interface="eth0";
voidusage(char*p){
if(strrchr(p,'/'))
p=strchr(p,'/')+1;
printf("%s[options]
"
"-i--iface=IFACESpecify ethernet interface(%s)
"
"-d--delay-up=SECSSpecify delay time(%i)
"
"-h--helpShow this help
",
p,
interface,
delay_up);
}
voidparse_args(intargc,char*argv[]){
staticstructoptionlong_options[]={
{"iface",required_argument,0,'i'},
{"delay-up",required_argument,0,'d'},
{"help",no_argument,0,'h'},
{"version",no_argument,0,'v'},
{0,0,0,0}
};
intoption_index=0;
inthelp=0,_kill=0,_check=0,_version=0,_suspend=0,_resume=0,_info=0;
for(;;){
intc;
if((c=getopt_long(argc,argv,"ihv",long_options,&option_index))< 0)
break;
switch(c){
case'i':
interface=strdup(optarg);
printf("interface%s
",interface);
break;
case'd':
delay_up=atoi(optarg);
printf("delay_up%d
",delay_up);
break;
case'h':
usage(argv[0]);
break;
case'v':
printf("peng"ETHCHECKD_VERSION"
");
break;
default:
fprintf(stderr,"Unknown parameter.
");
exit(1);
}
}
}
staticvolatileintalarmed=0;
intmain(intargc,char*argv[]){
parse_args(argc,argv);
return0;
}
下面是测试结果
- 短选项
peng@ubuntu:~/work/test$./param-h
param[options]
-i--iface=IFACESpecify ethernet interface(eth0)
-d--delay-up=SECSSpecify delay time(0)
-h--helpShow thishelp
peng@ubuntu:~/work/test$./param-v
peng 1.1
peng@ubuntu:~/work/test$./param-vh
peng 1.1
param[options]
-i--iface=IFACESpecify ethernet interface(eth0)
-d--delay-up=SECSSpecify delay time(0)
-h--helpShow thishelp
peng@ubuntu:~/work/test$./param-i eth3-d 15
interface eth3
delay_up 15
peng@ubuntu:~/work/test$./param-i eth3-d 15-h
interface eth3
delay_up 15
param[options]
-i--iface=IFACESpecify ethernet interface(eth3)
-d--delay-up=SECSSpecify delay time(15)
-h--helpShow thishelp
-
长选项
peng@ubuntu:~/work/test$./param--help
param[options]
-i--iface=IFACESpecify ethernet interface(eth0)
-d--delay-up=SECSSpecify delay time(0)
-h--helpShow thishelp
peng@ubuntu:~/work/test$./param--version
peng 1.1
peng@ubuntu:~/work/test$./param--iface eth3--delay-up 15
interface eth3
delay_up 15
talk is cheap!
testthis code!
快操练起来吧!!!
-
Linux
+关注
关注
87文章
10994浏览量
206772 -
C语言
+关注
关注
180文章
7534浏览量
128988 -
数组
+关注
关注
1文章
409浏览量
25597
原文标题:Linux程序之可变参数&&选项那些事
文章出处:【微信号:玩点嵌入式,微信公众号:玩点嵌入式】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论