Linux(程序设计):19—main函数参数处理(getopt、getopt_long)

一、程序参数

  • 当一个用C语言编写的Linux或UNIX程序运行时,它是从main函数开始的。对这些程序而言,main函数的声明如下所示:
  • argc:​程序参数个数
  • argv:​一个代表参数自身的字符串数组,argv[0]必为程序名,argv[1]开始才是程序的参数
int main(int argc,char *argv[])
  • 你可能也会看到Linclude是c语言关键字吗inux的C程序将main函数简单的声明为:
  • 这样的main函数返回值类型默认为int
  • argc和argv仍在,但是由于没有声明它们,就不能使用它们
main()

例如

​./myprog left right 'and center'​

  • argc:4
  • argv:{"myprog","left","right","center"字符串类型}

二、程序参数的使用规范

  • 命令系统运维工程师行选项很常用,因此按相同的方式使用它们对程序的使用者来说是很有好处的。过去,每个工具程序采用它们各自的方式来使用命令行选项,这带来了一些混乱。例如,请看下面这些命令使用 参数的方式:
  • ①我们建议在应用程序中,所有的命令行开关都应以一个短横线开头,其后包含单个字母或数字。 如果需要,不带后续参数的选项可以在一个短横线后归并到一起。所以,上面的两个ls命令示例就遵循了以上准则
  • ②如果某个选项需要值,字符串类型则该值应作为include和including的区别独立的参数紧跟在该选项后。dd命令示例违背了 这一准则,因为它使用了多字符的选项,而且选系统/运维项未以短横线开头(if=/dev/fd0),而tar命令则把 选项和它main函数可以在任何地方出现们的值完全分开!
  • ③我们建议最好能字符串类型为单字符开关增加一个更长的、更有意义的开关名,这include和contain的区别样 你就可以使用-h或--help选项来获得帮助了

演示案例

//args.c

#include <stdio.h>

int main(int argc,char *argv[])
{
int count;
for(count=0;count<argc;count++){
if(argv[count][0]=='-'){
printf("option:%s\n",argv[count]+1);
}else{
printf("argument:%s\n",argv[count]);
}
}
return 0;
}


                                            Linux(程序设计):19---main函数参数处理(getopt、getopt_long)

三、命令行开关函数(getopt)

#include <unistd.h>
int getopt(int argc, char * const argv[],const char *optstring);

extern char *optarg;
extern int optind, opterr, optopt;

参数

  • argc,argv:​分别为main函数的argc和main函数的位置argv
  • optstring:​字符串列表,该字符串告诉getopt哪些选项可用,以及它们是否有关联值
  • 列表中的一个字符代main函数什么意思表一个单字符选项,如果一个字符后面紧跟着一个冒号(:),代表这个选项有一个关联值作为下一个参数

返回值

  • getopt的include是c语言关键字吗返回值是argv数组中的下一个选项字符(如果有的话)。循环调用getopt就可以依次得 到每个选项

getopt函数的行为main函数必须位于程序的最前面吗

  • ①如果选项有一个关联值,则外部​变量optarg​指向这个值
  • ②如果选项处理完毕,getopt返回-1
  • ③特殊参数“--”将使getopt停linux命令止扫描选项
  • ④如果遇到一个无法识别的选项,getopt返回一个问号(?),并把main函数是c程序的主函数它保存到​外部变量optopt中
  • ⑤如果一个选项要求有一个关联值(例如例子中的-f),但用户并未提供这个值,getopt通常将 返回一个问号(?)。如果我们将选项字符串(optstring)的第一个字符设置为冒号(:),那么getopt将在用户未提供值的情况下返回冒号(字符串类型:)而不是问号(?)

optind变量main函数的作用

  • 外部变量optind被设置为下一个待处理参数的索引。getopt利用它来记录自己的进度。程序很少需要对这个变量进行设置。当main函数可以在任何地方出现所有选项参数都处理完毕后,optind将指向argv数组尾部可以main函数的位置找到其余参数的位置
  • 有些版本的getopt会在第一个非选项参数处停下来,返回-1并设置optind的值。但是Linux版本不同,如linux是什么操作系统果参数中出现了非选项参数,那么getopt​重写了argv数组,把所有系统运维主要做什么非选项参数集中在一起,非选项参数从argv[optind]位置main函数必须位于程序的最前面吗开始字符串转数组。对GNU版本 的getopt而言,这一行为是由环境变量POSIXLY_CORRECT控制的,如果它被设置,getoptincludes就会在第 一个非选项参数处停下来

opterr变量

  • 还有些getopt版本会在遇到未知选项时打印出错信息
  • 注意,根据 POSIX规范的规定,如果opterr变量是非main函数可以在任何地方出现零值,getopt就会向stderr打印一条出错信息

案例

getopt(argc,argv,"if:lr");

  • 这个调用告诉我们,getopt会对-i、-f、-l、-r选项进行操作,由于f后面跟着一个冒号(:),因此-f选项的后面要跟着一个值

编程案例

//argopt.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc,char *argv[])
{
int opt;

//对选项参数进行处理,处理完毕之后getopt返回-1
//opt为每次返回的选项
while((opt=getopt(argc,argv,":if:lr"))!=-1)
{
switch(opt)
{
case 'i':
case 'l':
case 'r':
printf("option:%c\n",opt);
break;
case 'f':
printf("filename:%s\n",optarg);
break;
case ':':
printf("option needs a value\n");
break;
case '?':
printf("unknow option:%c\n",optopt);
break;
}
}

//所有选项都处理完毕后,程序像以前一样把其余参数都打印出来,但这里从optind位置开始
for(;optind<argc;optind++){
printf("argument:%s\n",argv[optind]);
}

exit(EXIT_SUCCESS);
}
  • 运行程序①:
  • -i、-l、-r选项依字符串转数组次被识别
  • 遍历到'hi there'的时候,由于getopt的字符串列表中没有,所以就跳过了接着遍历下面的-f选项
  • -f选项后面跟着系统运维工程师fread.c,系统会将fread.c这个字符串保存在optarg中,我们通过打印optarg来打印fread.c
  • 由于-q选项没有在getopt函数的字符串列表中,所以显示“unknow option”


                                            Linux(程序设计):19---main函数参数处理(getopt、getopt_long)

  • 运行程序②:
  • -f没有执行值,因为getopt的第三个参数字符串是以“:”开头的,因此glinux是什么操作系统etopt返回的是“:”,因此匹配第5个cmain函数必须放在程序的开头ase,打印“option needs a value”


                                            Linux(程序设计):19---main函数参数处理(getopt、getopt_long)

  • 运行程序③:
  • 由于我们将-ilinux操作系统基础知识参数写到了-f的后面,程序误认为-i是-f选项的值,因此打印了下面的结果


                                            Linux(程序设计):19---main函数参数处理(getopt、getopt_long)

四、getopt_long

#include <getopt.h>
int getopt_long(int argc, char * const argv[],const char *optstring,
const struct option *longopts, int *longindex);
  • GNU C函 数库包含geto字符串转数组pt的另一个版本,称作getopt_long,它接受以双划线(--)开始的长参数

参数

  • argc,argv:​main函数的参数
  • optstring:​字符串列表
  • longopts:​一个struct option的结构体,描述每个长选项并告诉getopt_long如何处理它们。长选项数组由一些类型为struct option的结构组成,每个结构描述了一个长选项includestdioh是什么意思的行为。该数 组必须以一个包含全0的结构结尾。
  • longlinux是什么操作系统i#includende字符串类型x:​一个变量指针,它可以作为optind的长选项版本include用法使用。对于每个识别的长选项,它在长选项数组中的索引就写入该变量

struct option结构体

  • 要使用该结构体,必须定义_GNU_SOURCE宏定义

#include <getopt.h>
#define _GNU_SOURCE
structlinux重启命令 option {
cons#includet chaincluded是什么意思r *namelinux操作系统基础知识;
int has_arg;
i系统运维工作内容nt *flag;
int val;
};

  • nlinux操作系统基础知识ame:​长选项的名字。缩写也可以接受,只要不与其他选项混淆
  • has_arglinux命令​该选项是否带参数。0表示不带参数,1表示必须有一个参数,2表示有一个可选参数
  • linux重启命令f字符串常量lag:​设置为NULL表示当找到该选项时,getopt_loninclude的介词g返回在成员vlinux命令al里给出的值。否则, getoptmain函数_long返回0,并将val的值写入flag指向的变量
  • val:​getopt_long为该选项返回的值

演示案例

//longopt.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>

#define _GNU_SOURCE
int main(int argc,char *argv[])
{
int opt;
struct option longopts[]={
{"initialize",0,NULL,'i'},
{"file",1,NULL,'f'},
{"list",0,NULL,'1'},
{"restart",0,NULL,'r'},
{0,0,0,0},
};

//本例中,我们不需要longindex参数,将其置位NULL
while((opt=getopt_long(argc,argv,":if:lr",longopts,NULL))!=-1)
{
switch(opt)
{
case 'i':
case 'l':
case 'r':
printf("option:%c\n",opt);
break;
case 'f':
printf("filename:%s\n",optarg);
break;
case ':':
printf("option needs a value\n");
break;
case '?':
printf("unknow option:%c\n",optopt);
break;
}
}

for(;optind<argc;optind++){
printf("argument:%s\n",argv[optind]);
}

exit(EXIT_SUCCESS);
}


                                            Linux(程序设计):19---main函数参数处理(getopt、getopt_long)
                                            Linux(程序设计):19---main函数参数处理(getopt、getopt_long)