0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux程序之可变参数&&选项那些事

Dp1040 来源:一口Linux 2023-11-25 09:56 次阅读

一、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关系如下:cddadca2-8b2a-11ee-939d-92fbcf53809c.png

二、选项

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程序之可变参数&&选项那些事

文章出处:【微信号:玩点嵌入式,微信公众号:玩点嵌入式】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Proteus程序AMP应用LEDDISP

    Proteus程序AMP应用LEDDISP
    发表于 01-18 17:41 2次下载

    Proteus程序AMP应用LEDCON

    Proteus程序AMP应用LEDCON
    发表于 01-18 17:41 8次下载

    Proteus程序AMP应用TIMERLED

    Proteus程序AMP应用TIMERLED
    发表于 01-18 17:43 4次下载

    Proteus程序AMP应用TimeLCD

    Proteus程序AMP应用TimeLCD
    发表于 01-18 17:43 5次下载

    Proteus程序AMP应用UART0

    Proteus程序AMP应用UART0。
    发表于 01-18 17:43 2次下载

    Proteus程序AMP应用TIMEROUT

    Proteus程序AMP应用TIMEROUT
    发表于 01-18 17:43 6次下载

    Proteus程序AMP应用POWER

    Proteus程序AMP应用POWER。
    发表于 01-18 17:44 5次下载

    Proteus程序AMP应用LEDHEX

    Proteus程序AMP应用LEDHEX。
    发表于 01-18 17:44 5次下载

    存储类&amp;作用域&amp;生命周期&amp;链接属性

    目录前言一、存储类&amp;amp;作用域&amp;amp;生命周期&amp;amp;链接属性的
    发表于 12-09 15:51 5次下载
    存储类&<b class='flag-5'>amp</b>;作用域&<b class='flag-5'>amp</b>;生命周期&<b class='flag-5'>amp</b>;链接属性

    2021 Kubernetes on AI &amp;amp;amp;amp; Edge Day圆满举行 共探边缘云融合

    2021年12月11日-12日,由Linux基金会、LF AI &amp;DATA、LF Edge、CNCF、LFN等开源社区联合举办,开源科技OSTech和西丽湖人才服务中心协办的Kubernetes on AI &amp;
    的头像 发表于 12-16 09:43 5026次阅读
    2021 Kubernetes on AI &<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>; Edge Day圆满举行 共探边缘云融合

    如何区分Java中的&amp;amp;和&amp;amp;&amp;amp;

    首先给i赋值为0,如果i大于10,并且i++等于1,则输出“错误”和i的值。否则输出“正确”和i的值。分别用&amp;和&amp;&amp;运行,观察运行结果的不同。
    的头像 发表于 02-24 10:46 1230次阅读
    如何区分Java中的&<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;和&<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;&<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;

    if(a==1 &amp;amp;&amp;amp; a==2 &amp;amp;&amp;amp; a==3),为true,你敢信?

    接下来咱们来尝试解决这个问题。假设 if(a==1&amp;&amp;a==12)是等于 true的,那么a肯定不可能是一个“普通的变量”。它势必要有能力在执行的时候能够动态改动值。
    的头像 发表于 05-08 11:01 759次阅读
    if(a==1 &<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;&<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>; a==2 &<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;&<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>; a==3),为true,你敢信?

    HarmonyOS &amp;amp;amp;amp;润和HiSpark 实战开发,“码”上评选活动,邀您来赛!!!

    出色的系统 助力优秀的设备 为应用开发者带来丰富的体验与想象空间 正如当HarmonyOS遇见润和HiSpark 这万物互联的时代 将由你的&amp;lt; 代码 &amp;gt;来定义
    的头像 发表于 04-11 15:33 833次阅读
    HarmonyOS &<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;润和HiSpark 实战开发,“码”上评选活动,邀您来赛!!!

    你使用shell脚本中的2&amp;gt;&amp;amp;1了吗?

    run_cmax > ./starrc_cmax.logs 2>&amp;1中的 2>&amp;1是啥意思?
    的头像 发表于 07-30 14:44 1072次阅读

    摄像机&amp;amp;amp;雷达对车辆驾驶的辅助

    摄像机&amp;amp;雷达担负着可辅助驾驶员安全驾驶的、高级驾驶辅助系统的传感功能。尼得科正在进一步推进摄像机&amp;amp;雷达的高性能化进程。
    的头像 发表于 11-26 10:02 526次阅读
    摄像机&<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;<b class='flag-5'>amp</b>;雷达对车辆驾驶的辅助