在 glibc 中提供了一个通用的参数解析库,包括了短参以及长参的使用。
短参
通过 getopt() 函数实现,可以通过循环调用解析参数,当没有多余选项时,会直接返回 -1 。
全局变量
在 getopt() 函数的实现中,引入了很多全局变量。
optind
int optind 标识在 argv 中将要检查的下个参数,初始化为 1,如果多次调用 getopt() 或者需要重头开始解析,那么就需要重新将 optind 配置为 1 。
optarg
char *optarg 当使用带参数的选项时,会将 argv[] 中的指针指向该变量。
通过 : 标识选项后有一个参数,可以通过 -c color 或者 -ccolor 使用,注意,一定不要使用 -c=color 方式,此时返回的是 =color 。
opterr optopt
当遇到不支持的选项时,会在 stderr 中打印错误信息 invalid option -- 'x' (可以通过将 opterr 设置为 0 不打印),同时将选项保存在 optopt 中,并返回 ? 。
示例
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <stdbool.h>
int main(int argc, char **argv)
{
int option, delay = 0;
opterr = 0;
while ((option = getopt(argc, argv, "abc:d::")) != -1) {
switch (option) {
case 'a':
fprintf(stdout, "option -a\n");
break;
case 'b':
fprintf(stdout, "option -b\n");
break;
case 'c':
fprintf(stdout, "option -c %s\n", optarg);
break;
case 'd':
delay = optarg ? atoi(optarg) : 1;
fprintf(stdout, "option -d %d\n", delay);
break;
case '?':
fprintf(stderr, "unsupport options '%c'\n", optopt);
exit(EXIT_FAILURE);
}
}
/* Print remaining arguments. */
for (; optind < argc; optind++)
printf("%s\n", argv[optind]);
return 0;
}
注意事项
只能通过 - 标识选项,对于 getopt() 来说,不能使用 -- 否则会被认为是 - 选项。
--a 报错,无法识别 `-` 选项
-a opt -b 可以正确识别-a和-b选项,并剩余opt参数
-c color -ccolor 带有值的参数
长参
getopt_long() 与 getopt() 类似,可以通过 -- 指定长参数,同时通过函数入参可以指定短参数,如果想只支持长参数,那么需要将 optstring 设置为 "" 而非 NULL 。
可以使用 --args=param 或者 --args param 指定参数,在解释参数时,需要初始化如下的数组。
struct option {
const char *name; // 选项名称
int has_arg; // no_argument/0 required_argument/1 optional_argument/2
int *flag; // 可以是NULL或者指针
int val; // 根据flag返回
};
根据配置中的 flag 和 val 决定了参数的解析方式,
flag != NULL
会将 val 中的值赋值到 flag 指针所指向的变量,而 getopt_long() 函数会返回 0 ,比较适合整数类型的设置。
flag == NULL
在函数 getopt_long() 中会返回 val 中指定的值,为了方便处理,最好兼容 optstring 中指定的值。
示例
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
int main(int argc, char **argv)
{
int c, idx, verbose = 0;
struct option options[] = {
{"verbose", no_argument, &verbose, 1 },
{"add", no_argument, NULL, 'a'},
{"change", required_argument, NULL, 'c'},
{"delete", required_argument, NULL, 0 },
{0, 0, 0, 0}
};
while (1) {
idx = 0;
c = getopt_long(argc, argv, "ac:d:", options, &idx);
if (c == -1) /* Detect the end of the options. */
break;
switch(c) {
case 0:
/* If this option set a flag, do nothing else now. */
if (options[idx].flag != NULL)
break;
printf("option '%s'", options[idx].name);
if (optarg)
printf(" with arg '%s'", optarg);
printf("\n");
break;
case 'a':
fprintf(stdout, "option -a\n");
break;
case 'c':
printf ("option -c with value '%s'\n", optarg);
break;
case '?':
break;
default:
exit(EXIT_FAILURE);
}
}
/* Print remaining arguments (not options). */
for (; optind < argc; optind++)
printf("%s\n", argv[optind]);
return 0;
}