一、目的
相信第一次接触linux的小伙伴在使用命令行时肯定有这样的疑惑,命令行各种各样的选项和选项参数是怎样实现的(各个命令的选项的含义可以通过man手册查看)。
二、介绍
在正式介绍之前,我们先来看一下命令行选项的使用(以ls(查看目录下的内容)为例)
1.不带选项
ls
2.带一个选项
ls -l
3.带多个选项
ls -a -l
4.多个选项合并
ls -al
另外有些选项必须带参数,有些选项参数非必须(即可以带参数也可以不带参数)
从上面的示例可以看到选项一般以'-'开头,后面紧跟至少一个字母(建议使用a-z A-Z)(如果'-'后面存在多个字母那么选项会合并)这种形式的选项叫做短选项;如果是以"--"开头那么代表长选项(本篇不介绍),例如ls就有一个"--color=when" 选项。
如果要实现上述类似的功能,可以用到getopt函数(只支持短选项)
其中argc/argv来自int main(int argc, char **argv);
optstring指定选项列表(举例来说optstring="abcd:e::")
其中a代表命令行参数"-a"
b代表命令行参数"-b"
c代表命令行参数"-c"
d代表命令行参数"-d123"或者"-d 123",其中123就是选项参数
e代表命令行参数"-e123"或者"-e",注意此处的123是选项参数,‘e’和"123"之间不能有空格
optind记录下一个命令行参数,默认值为1,也就是从argv[1]开始解析
optopt记录当前解析的选项
optarg记录当前选项的参数,如果未指定参数则为NULL;例如"-e123"选项optarg="123","-e"选项optarg=NULL
opterr默认为1,当输入不识别的选项或者需要选项参数的选项没有选项参数时会报错
getopt的返回值可以是指定的optstring里面的字符,也可能是-1;也可以是'?'和':';具体请看下面的说明。
使用示例
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int opt;
//opterr = 0; //(1)
while ((opt = getopt(argc, argv, "abcd:e::-")) != -1) {
printf("current char: (opt)%c-(optopt)%c, optind: %d\n", opt, optopt, optind);
switch (opt) {
case 'a':
break;
case 'b':
break;
case 'c':
break;
case 'd':
printf("arguments: %s\n", optarg);
break;
case 'e':
printf("arguments: %s\n", optarg ? optarg : "none");
break;
case ':':
case '?':
default:
printf("invalid parameter\n");
break;
}
}
printf("===extra arguments===\n");
while (optind < argc) {
printf("%s\n", argv[optind++]);
}
printf("=====================\n");
return 0;
}
编译
gcc getopt_test.c -o getopt_test
测试
因为选项d需要指定选项参数,如果没有指定选项参数,那么getopt默认会打印错误信息,告知错误原因,并且getopt返回值为'?'
./getopt_test -d
./getopt_test: option requires an argument -- d
current char: (opt)?-(optopt)d, optind: 3
invalid parameter
===extra arguments===
=====================
./getopt_test -x
./getopt_test: illegal option -- x
current char: (opt)?-(optopt)x, optind: 2
invalid parameter
===extra arguments===
=====================
如果不需要有这样的错误输出可以设置opterr=0,请查看代码注释(1)
如果我们设置了otperr=0,那么怎么区分是指定了不支持的参数,还是选项参数未指定呢?
有两种方法:
第一种,通过判断optopt的值,如果optopt的值不是optstring里面的字符,就代表是非有效选项字符;
第二种,在optstring的开头添加':',举例设置optstring为":abcd:e::",这个时候通过getopt返回值是'?'(选项不存在)还是':'(选项未指定参数)来区分 。
在实际使用时,我们的命令行不仅仅有选项和选项参数,还有一些额外的参数
./getopt_test -a -b -c x y z
current char: (opt)a-(optopt)a, optind: 2
current char: (opt)b-(optopt)b, optind: 3
current char: (opt)c-(optopt)c, optind: 4
===extra arguments===
x
y
z
=====================
上面的x/y/z就是命令行额外参数(位置参数)
如果某个位置参数是'-a'时,我们应该怎么处理呢?(-a会被认为是选项a)
./getopt_test -a -b -c -- -a
current char: (opt)a-(optopt)a, optind: 2
current char: (opt)b-(optopt)b, optind: 3
current char: (opt)c-(optopt)c, optind: 4
===extra arguments===
-a
=====================
通过"--"我们可以将位置参数和选项隔离;
选项参数是可以以‘-’开头的(不建议)
./getopt_test -d -abc
current char: (opt)d-(optopt)d, optind: 3
arguments: -abc
===extra arguments===
=====================
./getopt_test -d-abc
current char: (opt)d-(optopt)d, optind: 2
arguments: -abc
===extra arguments===
=====================
"-abc"会被认为是"-d"的选项而不是选项"-a -b -c"
以上,就是getopt函数的基本内容。