现在开始慢慢学习下上层开发,因为要为底层写些工具。首先从命令行参数的过滤获取开始,有两个函数用来操作命令行参数,以前我获取命令行都是自己用argv和argc做个循环获取的,其中各种转换和判断有点繁琐。现在学习下这两个函数怎么使用,可以方便后期的开发;
在学习这两个函数之前先说明下:Linux的命令行选项有两种类型:短选项和长选项,前者以 '-' 作为前导符,后者以 '--' 作为前导符
getopt函数
getopt()函数是专门用来处理命令行参数短选项的,不能处理长选项参数;
头文件:#include<unistd.h>
函数原型:int getopt(int argc,char * const argv[ ],const char * optstring);
参数分析:
int argc 和 char *argv[] 这两个参数是直接从main函数中接过来的;
char *optstring 是对应的选项字符串,比如:"ab:c::d::",这就表示在输入的命令行中要和这个字符串对应起来;(至于怎么对应后面会分析)
该函数有个返回值,比如,这样调用该函数:./a.out -a -b btest -cctest -d;那么返回值就会分别为: a、b、c、d、-1;最后没有参数了会返回-1;所以这样就可以做个while循环和-1比较,获取到所有参数;然后通过switch()就可以很好的操作参数;
上面提到的都是正常的返回,如果调用函数时有个短选项在optstring没有与其对应的,则该函数会返回:?;或者./a.out -n 后面没有跟参数(后面什么都没有,如果跟了-s,则会把-s当作-n的参数),这时候也会返回?;
现在来说明char *optstring 对应的命令行参数选项字符串(名称不知道怎么叫,大概意思就是对应命令行参数);
还是上面那字符串"ab:c::d", a 表示有个短选项 -a,其后面不跟参数(一定不能有参数); b: 表示有个短选项 -b,其后面跟一个参数(一定要跟参数); c:: 表示有个短选项 -c,其后面可以跟参数也可以不跟,跟参数时不能有空格; 这是根据字符后面的冒号来区分的,一个冒号是一定跟一个参数;两个冒号是随意跟不跟参数;没有冒号则一定不能跟冒号;
上面可以对应这个调用:./a.out -a -b btest -cctest -d
-a 后面没有带参数;-b 后面带了个参数btest,其中有空格隔开;-c 后面带了个参数ctest,其中没有用空格隔开;-d 后面没有带参数;
再来讲下几个自带的全局变量;
char *optstr;这个变量不需要自己定义,我这里写char *是为了说明该参数的类型;这个参数指向短选项后面的参数,如上面调用:执行-a时,optstr=NULL; 执行-b时,optstr=btest;执行-c时,optstr=ctest;执行-d时,optstr=NULL;(如果有短选项后面的是数值,这时候该数值也是做字符串;如果要用数值,则需要转换)
int optind;这个变量也不需要自己定义就可以直接使用,或者用extern int optind 也可以;这个变量指向下一个需要解析的参数位置,初始值为1;(./a.out为参数0)
int opterr;这个变量好像是打印错误信息的;默认是1,这时候如果getopt()函数出错时(可能没有对应的短选项)则会报:./a.out: invalid option -- 'x' 类似这样的错误。如果不想出现这个错误信息可以设置opterr为0就可以。
int optopt;这个变量是存放出错时的信息;比如,./a.out -n 则optopt=n;./a.out -n yzh -x 则optopt = x;
这里利用下面的实例代码的运行来说明上面的一些分析(opterr = 0的情况):
[yzh@yzh test]$ ./a.out -nyzh -s -g1 -c2 -x
n:sg::c::h (这个是getopt()函数中第三个参数:对应选项字符串参数)
opt:n, optarg:yzh, optind:2, opterr:0, optopt:, argv[optind]:-nyzh
opt:s, optarg:(null), optind:3, opterr:0, optopt:, argv[optind]:-s
opt:g, optarg:1, optind:4, opterr:0, optopt:, argv[optind]:-g1
opt:c, optarg:2, optind:5, opterr:0, optopt:, argv[optind]:-c2
opt:?, optarg:(null), optind:6, opterr:0, optopt:x, argv[optind]:-x
下面是opterr为默认值时的打印
opt:c, optarg:2, optind:5, opterr:1, optopt:, argv[optind]:-c2
./a.out: invalid option -- 'x'
opt:?, optarg:(null), optind:6, opterr:1, optopt:x, argv[optind]:-x
实例代码:(这里只是为了说明知识点)
#include<stdio.h>
#include<unistd.h>
void opt_usage()
{
printf("\nDescription:\n");
printf("\tA student info\n\n");
printf("Usage:\n");
printf("\t-n, student name\n");
printf("\t-s, student sex\n");
printf("\t-g, student in grade\n");
printf("\t-c, student in class\n");
printf("\t-h, help\n");
}
int main(int argc, char **argv)
{
// extern char *optarg;
// extern int optind;
// extern int opterr;
// extern int optopt;
int opt, sex, grade, class;
char *name=NULL;
sex=1;
printf("n:sg::c::h\n");
while ((opt = getopt(argc, argv, "n:sg::c::h")) != -1) {
printf ("\nopt:%c, optarg:%s, optind:%d, opterr:%d, optopt:%c, argv[optind]:%s\n",
opt, optarg, optind, opterr, optopt, argv[optind-1]);
switch (opt) {
case 'n':
name = optarg;
break;
case 's':
sex = 0;
break;
case 'g':
grade = strtoul(optarg, NULL, 10);
break;
case 'c':
class = strtoul(optarg, NULL, 10);
break;
case 'h':
opt_usage();
return 0;
default:
opt_usage();
return -1;
}
}
printf("\n\nA student info:\n");
printf("name:%s\n", name);
printf("sex:%d\n", sex);
printf("grade:%d\n", grade);
printf("class:%d\n", class);
opt_usage();
return 0;
}
getopt_long函数
前面的getopt()函数只支持短选项参数,也就是说只能用 -a 1 或者 -b 或者 -ctest;而getopt_long()函数可以支持短选项参数,同时也可以支持长选项参数;如下面:假设struct option long options[] 数组中有这样一条 {"name", required_argument, NULL, 'n'};那么调用时可以这么写:./a.out --name yzh (长选项参数);也可以这么写:./a.out -n yzh(短选项参数);(提到的这个数组后面会说下);
在getopt()函数分析时说的一些知识点,这里都可以使用。这里说下新的知识点:
函数原型:int getopt_long(int argc, char *argv[],char *optstring,struct option *longopts, int *longindex);
参数分析:前面两个参数 argc 和 argv都是从main函数接受过来的。第三个参数和getopt()函数中的一样,用作短选项和是否带参数的表示字符串,比如:"n:s::g::c:H";
第四个参数: struct option *longopts;是一个#include<getopt.h>头文件中定义好的数组,这个数组非常重要,是短选项和长选项的链接的关键;数组定义如下:
struct option{
const char *name;
int has_arg;
int *flag;
int val;
};
name是长选项的名称,一般可以这样使用:--name 参数(如果后面有参数的话);
has_arg:是表示该选项后面是否接参数,0 == no_argument 不接参数;1 == required_argument 后面一定要接参数;2 == optional_argument 后面可以接也可以不接参数;其中 no_argument、required_argument、optional_argument是宏定义,其实就是0、1、2;
flag 一般设置为NULL,这样getopt_long()函数就会返回val的值了。如果不设置为NULL,则会把对应的val的值保持到flag指向的变量中(flag是int指针),这时候getopt_long()函数返回0;
val 为对应的短选项字符,和getopt_long()函数中的第三个参数对应的;
实例如下:
struct option long_options[] = {
{"name", required_argument, NULL, 'n'},
{"sex", optional_argument, &sex, 's'},
{"grade", optional_argument, NULL, 'g'},
{"class", required_argument, NULL, 'c'},
{"help", no_argument, NULL, 'H'},
{0, 0, 0, 0}
};
getopt_long()函数的第五个个参数,一般设置为NULL;如果不为NULL,那么变量会被赋值长选项在longopts中的索引值;
实例代码:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<getopt.h>
void print_usage()
{
printf("\nUsage:\n");
printf("\t--name=student name\n");
printf("\t-s, --sex=student sex\n"
"\t\tif no usage ,sex is 0 means man\n\n");
printf("\t-g, --grade=student in grade\n");
printf("\t-c, --class=student in class\n");
printf("\t-h, --help\n");
}
int main(int argc, char* argv[])
{
int opt, grade, class, sex = -1;
char *name = NULL;
struct option long_options[] = {
{"name", required_argument, NULL, 'n'},
{"sex", optional_argument, &sex, 's'},
{"grade", optional_argument, NULL, 'g'},
{"class", required_argument, NULL, 'c'},
{"help", no_argument, NULL, 'H'},
{0, 0, 0, 0}
};
printf("n:s::g::c:H\n");
while ((opt = getopt_long(argc, argv, "n:s::g::c:H", long_options, NULL)) != -1) {
printf ("\nopt:%c, optarg:%s, optind:%d, opterr:%d, optopt:%c, argv[optind]:%s\n",
opt, optarg, optind, opterr, optopt, argv[optind-1]);
switch (opt) {
case 'n':
name = optarg;
printf("name:%s\n", name);
break;
case 's':
printf("sex:%d\n", sex);
if (sex == -1)sex = 0;
//printf("sex:%d, %s", sex, sex > 0 ? "gilr":"mem");
break;
case 'g':
if (!strcmp(argv[optind-1], "-g"))grade = 1;
else
grade = strtoul(optarg, NULL, 10);
break;
case 'c':
class = strtoul(optarg, NULL, 10);
break;
case 'H':
print_usage();
return 0;
default:
print_usage();
return -1;
}
}
printf("A student info:\n"
"name:%s\n"
"sex:%s\n"
"grade:%d\n"
"class:%d\n",
name, sex > 0 ? "gilr" : "men", grade, class)
;
return 0;
}
转载地址:
http://blog.csdn.net/yuzhihui_no1/article/details/47789771