前文《 C语言(Head First C)-4_2:创建小工具:做一件事并把它做好》
十个程序有九个需要选项;聊天程序有“系统设置”;游戏有调整难度的选项;而命令行工具需要有命令行选项;
命令行选项是一些小开关,他们经常出现在命令行中;
如:
ps -ae //显示所有进程,包括后台运行的进程;
很多程序都会使用命令行选项,因此有一个专门的库函数,可以用它来简化处理过程;
这个库函数叫getopt(),每次调用都会返回命令行中下一个参数;说的可能比较抽象,我们接着来;
unistd.h头文件不属于C标准库,而是POSIX库中的一员;POSIX的目标是创建一套能够在所有主流操作系统上使用的函数;
-库函数getopt(),每次调用都会返回命令行中下一个参数;
-int getopt(int argc,char * const argv[ ],const char * optstring);
-此函数会返回在argv 中下一个的选项字母,此字母会对应参数optstring 中的字母。如果选项字符串里的字母后接着冒号“:”,则表示还有相关的参数,全域变量optarg 即会指向此额外参数。
-如果getopt()找不到符合的参数则会印出错信息,并将全域变量optopt设为“?”字符,如果不希望getopt()印出错信息,则只要将全域变量opterr设为0即可。
-getopt()使用optstring所指的字串作为短参数列表,象"1ac:d::"就是一个短参数列表。短参数的定义是一个'-'后面跟一个字母或数字,象-a, -b就是一个短参数。每个数字或字母定义一个参数。
- 其中短参数在getopt定义里分为三种:
1). 不带值的参数,它的定义即是参数本身。
2). 必须带值的参数,它的定义是在参数本身后面再加一个冒号。
3). 可选值的参数,它的定义是在参数本身后面加两个冒号 。
在这里拿上面的"1ac:d::"作为样例进行说明,其中的1,a就是不带值的参数,c是必须带值的参数,d是可选值的参数。
-参数不分先后顺序;
-当没有参数的最后的一次调用时,getopt()将返回-1。
-当解析到一个不在optstring里面的参数,或者一个必选值参数不带值时,返回'?'。
-当optstring是以':'开头时,缺值参数的情况下会返回':',而不是'?' 。
现在假设程序接收一组不同的选项:"1ac:d::"(对应程序中的getopt()函数使用的optstring所指代的短参数列表)
(Code4_1)
/*
* 库函数getopt(),每次调用都会返回命令行中下一个参数
*/
#include
#include //getopt()包含在的头文件
int main(int argc,char * argv[]) {
int ch;
opterr = 0;//全局变量
while ((ch = getopt(argc,argv,"1ac:d::")) != -1) {
printf("%i=>",optind);//全局变量
switch (ch) {
case 'c':
printf("%s\n",optarg);//全局变量
break;
case 'd':
printf("%s\n",optarg);
break;
default:
printf("%c\n",ch);
break;
}
}
argc -= optind;//读取选项之后的字符串列表,计算argc;
argv += optind;//读取选项之后的字符串列表,赋给argv;
for (int i = 0; i < argc; i++) {
printf("%s\n",argv[i]);
}
return 0;
}
运行时传递命令行参数如下:
./4_1 -1 -a -c value -d
log:
1
a
value
?
./4_1 -1 -a -c value -b
log:
1
a
value
?
./4_1 -1 -a -c value -d valued
log:
1
a
value
valued
上述代码循环调用getopt()函数处理命令行参数;
可以通过optind保存了getopt()从命令行读取了第几个选项;(修改程序)
运行:
./4_1 -1 -a -c value -d valued
1 2 3 4 5 6 7
log:
2=>1
3=>a
5=>value
7=>valued
最后可以使用下面这两行来跳过已读取的选项:
argc -= optind;//读取选项之后的字符串列表,计算argc;
argv += optind;//读取选项之后的字符串列表,赋给argv;(修改程序)
运行:./4_1 -1 -a -c value -d valued Landon Tokyo Beijing
2=>1
3=>a
5=>value
7=>valued
Landon
Tokyo
Beijing
在循环中,用switch语句处理了每个有效选项;设置短参数列表的字符串告诉getopt()函数,命令行选项该如何表示和识别;
循环结束后,为了让程序读取命令行参数,需要调整一下argv和argc变量,跳过所有选项;如上面的示例所见,最后argv数组将变成:Landon Tokyo Beijing,分别对应argv[0],argv[1],argv[2];
现在,经过一番处理之后,0号参数不再是程序名了,他指向了选项后的第一个命令行参数;
类似这种格式:程序名 命令行选项 命令行参数
-深入理解标准输入、标准输出、标准错误;
-使用重定向和自己创建的数据流读写文件;
-处理命令行参数和选项;
命令行选项是可以合并的,顺序也是无关的:-ac value <=> -c value -a;
命令行选项需要出现在命令行参数之前;
如果想要读取负数的选项参数,可以用--隔开参数和选项;-c -- -4;getopt()看到--就会停止读取选项,程序会把后面的内容当成不同命令行选项参数读取;
-main()函数有两个版本,一个有命令行参数,一个没有;
-命令行参数通过两个变量传递给main()函数,一个是参数的计数,一个是指针(指向参数字符串)数组;
-命令行选项是以‘-’开头的命令行参数;
-getopt()函数会帮助你处理命令行选项;
-为定义有效的选项,需要传给getopt()函数一个字符串,声明短参数列表;
-选项之后的':'表示该选项需要接收一个参数,getopt()会用optarg变量记录选项参数;
-读取完全部的选项之后,应该用optind变量跳过他们;
-printf()和scanf()使用标准输出和标准输入来交互;
-标准输出默认在显示器上显示数据;
-标准输入默认从键盘读取数据;
-标准错误专门用来输出错误消息;
-可以用重定向把标准输出,标准错误和标准输入连接到其他地方;
-可以用fprintf(stderr,...)把数据打印到标准错误;
-命令行参数以字符串指针数组的形式传递给main();
-用getopt()函数读取命令行选项很方便;
-可以用fopen("文件名","模式")创建你自己的数据流;
-三种模式分别为w(写入)、r(读取)、a(追加);