前言:最近在学习面向Linux系统进行C语言的编程,通过查询man手册和查看网络上的各种文章来获取一点点的知识,重点是看完手册还是一脸懵逼,搞不懂手册里面再说啥,而本篇文章将记录一下学习getopt_long的那些参数和返回值,希望能和大家讲清楚和说明白。
optstring分为三种选项 普通的,必须选项(:),可选选项(::),这个略,可以自行百度。
0. 可选选项
optstring 为 ":a::b:X"
Option syntax | Meaning |
---|---|
-a | OK, No argument provided (optional). |
-afoo | OK, argument is foo |
-a foo | Wrong, no space allowed with optional arguments. foo is considered a non-option argument. |
-bfoo | OK, argument is foo (required). |
-b foo | OK, argument is foo (required). |
-b | Wrong, option b requires an argument. |
注意:可选参数需要紧紧挨着写,不能有空格。
1. 未知的选项和缺少选项参数(Unknown Options and Missing Option Arguments)
当我们面对上面两个情况时候,如何进行处理
optstring为 "a:b:X"
当我们输入 -t 时候会出现 "未知的选项"的错误;
当我们输入 -a 而不输入选项参数时候,会出现"缺少选项参数"的错误;
一般情况下getopt会输出错误,但是我们希望我们能有相关的语句去处理或自定义提示。
我们通过在 optstring前面添加 ":",即 ":a:b:X"来进行解决,代码如下所示:
/* Notice the leading : in the option string */
opt
while ((opt = getopt(argc, argv, ":a:b:X")) != -1)
{
switch (opt)
{
case 'a':
printf("Option a has arg: %s\n", optarg);
break;
case 'b':
printf("Option b has arg: %s\n", optarg);
break;
case 'X':
printf("Option X was provided\n");
break;
case '?':
printf("Unknown option: %c\n", optopt);
break;
case ':':
printf("Missing arg for %c\n", optopt);
break;
}
}
假设这个程序输出为a.out, 则测试结果为:
Command line options | Output |
---|---|
./a.out -a | Missing arg for a |
./a.out -t | Unknown option: t |
./a.out -a one -t -X -b | Option a has arg: one Unknown option: t Option X was provided Missing arg for b |
./a.out -a one,two,three | Option a has arg: one,two,three |
./a.out -a "one two three" | Option a has arg: one two three |
我们查看文档, man 3 getopt 有如下文字,与咱们测试结果一致:
是说以":"开头的话,getopt不会打印错误同时针对 缺少选项参数的情况会返回 ":" ,这样可以让调用者或开发者区分这两种情况。通过添加":"将getopt关闭打印错误输出。
2. nonoption是否有序及获取相关值
nonoption,换一种写法 non-option也行,意思是非选项参数。
比如,我们执行gcc程序,如下所示:
gcc -Wall -Wextra main.c foo.c bar.c -O -o program -ansi -pedantic -Werror
哪个是non-option,其实就是前面没有"-"和"--"的,也就是 main.c/foo.c/bar.c, 而 program是-o选项的参数它不是nonoption。
我们先试一下:
#include <stdio.h> /* printf */
#include <getopt.h> /* getopt */
int main(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, ":a:b:X")) != -1)
{
switch (opt)
{
case 'a':
printf("Option a has arg: %s\n", optarg);
break;
case 'b':
printf("Option b has arg: %s\n", optarg);
break;
case 'X':
printf("Option X was provided\n");
break;
case '?':
printf("Unknown option: %c\n", optopt);
break;
case ':':
printf("Missing arg for %c\n", optopt);
break;
}
}
/* Get all of the non-option arguments */
if (optind < argc)
{
printf("Non-option args: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
return 0;
}
测试结果为:
Command line options | Output |
---|---|
./a.out x -a one y -X z | Option a has arg: one Option X was provided Non-option args: x y z |
./a.out x y z -a one -b two | Option a has arg: one Option b has arg: two Non-option args: x y z |
我们发现了一个奇怪的现象,就是这些非选项参数即使写在了其他选项参数的前面,但是它输出在了最后面,也就是说并没有按照书写的顺序进行输出。
原因是:getopt函数会将这些非选项参数放到数组argv的最后,当没有选项处理则返回-1并终止while循环。我们通过optind进行循环来获取后续的参数。
如果你想获取这些 非选项参数并且是按顺序进行输出,你需要在optstring前加"-",通过添加"-"来关闭getopt将non option移动到argv数组末尾。
#include <stdio.h> /* printf */
#include <getopt.h> /* getopt */
int main(int argc, char *argv[])
{
int opt;
/* Notice the leading minus sign - in the option string below */
/* Remember that the number one in single quotes '1' is not the */
/* same as the number one without quotes. '1' is ASCII 49 */
while ((opt = getopt(argc, argv, "-:a:b:X")) != -1)
{
switch (opt)
{
case 'a':
printf("Option a has arg: %s\n", optarg);
break;
case 'b':
printf("Option b has arg: %s\n", optarg);
break;
case 'X':
printf("Option X was provided\n");
break;
case '?':
printf("Unknown option: %c\n", optopt);
break;
case ':':
printf("Missing arg for %c\n", optopt);
break;
case 1:
printf("Non-option arg: %s\n", optarg);
break;
}
}
return 0;
}
当存在 non option出现时候,getopt_long函数返回值为 1
测试结果为:
Command line options | Output |
./a.out x y z -a foo | Non-option arg: x Non-option arg: y Non-option arg: z Option a has arg: foo |
./a.out x -a foo y -b bar z -X w | Non-option arg: x Option a has arg: foo Non-option arg: y Option b has arg: bar Non-option arg: z Option X was provided Non-option arg: w |
./a.out -t x -a foo -M y -b bar z -X w -b | Unknown option: t Non-option arg: x Option a has arg: foo Unknown option: M Non-option arg: y Option b has arg: bar Non-option arg: z Option X was provided Non-option arg: w Missing arg for b |
3.长选项以及短选项和长选项的关联
短选项的缺点是:
1. 选项个数受限,对于小程序这个倒没事,但是对于一个复杂的程序就显着不足,
2. 无法记住短选项的意思,比如 -a代表add,但是无法代表alter等
看一下rsync和wget你就会发现有很多的参数,而 getopt_long就是处理长选项的函数。
int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
argc 代表参数的个数
argv 代表保存各个参数的数组,每个参数是一个字符串
optstring 代表短选项的字符串
longopts 代表长选项的配置数组指针
longindex 代表 longopts数组的索引的指针
struct option
{
const char *name; /* name without -- in front */
int has_arg; /* one of: no_argument, required_argument, optional_argument */
int *flag; /* how the results are returned */
int val; /* the value to return or to put in flag */
};
static struct option long_options[] =
{
{"add", required_argument, NULL, 0 },
{"append", no_argument, NULL, 0 },
{"delete", required_argument, NULL, 0 },
{"verbose", no_argument, NULL, 0 },
{"create", required_argument, NULL, 0 },
{"file", optional_argument, NULL, 0 },
{NULL, 0, NULL, 0 }
};
如果flag为NULL,则这个 getopt_long函数返回 val
如果flag为指针,则将val放到flag指针中,这个getopt_long函数返回 0
测试程序如下:
#include <getopt.h> /* getopt */
#include <stdlib.h> /* exit */
#include <stdio.h> /* printf */
int main(int argc, char **argv)
{
int c;
while (1) {
int option_index = 0;
static struct option long_options[] =
{
{"add", required_argument, NULL, 'a'},
{"append", no_argument, NULL, 'p'},
{"delete", required_argument, NULL, 'd'},
{"verbose", no_argument, NULL, 'v'},
{"create", required_argument, NULL, 'c'},
{"file", optional_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
/* Still need to provide an option string for the short options */
c = getopt_long(argc, argv, "-:a:pd:vc:f::", long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf("long option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
case 1:
printf("regular argument '%s'\n", optarg);
break;
case 'a':
printf("option a with value '%s'\n", optarg);
break;
case 'p':
printf("option p\n");
break;
case 'd':
printf("option d with value '%s'\n", optarg);
break;
case 'v':
printf("option v\n");
break;
case 'c':
printf("option c with value '%s'\n", optarg);
break;
case 'f':
printf("option f with value '%s'\n", optarg ? optarg : "NULL");
break;
case '?':
printf("Unknown option %c\n", optopt);
break;
case ':':
printf("Missing option for %c\n", optopt);
break;
default:
printf("?? getopt returned character code %c ??\n", c);
}
}
测试结果为:
Command line | Output |
---|---|
./a.out --delete=foo -c5 --add=yes --append | option d with value 'foo' option c with value '5' option a with value 'yes' option p |
./a.out --d=foo --ad=yes --ap | option d with value 'foo' option a with value 'yes' option p |
./a.out --create=5 --create 6 --c=7 --c 8 | option c with value '5' option c with value '6' option c with value '7' option c with value '8' |
./a.out --file=5 --file 6 --file7 | option f with value '5' option f with value 'NULL' regular argument '6' Unknown option |
--d能匹配上--delete,--ad能匹配上--add,--ap能匹配上--append,--c能匹配上--create
4. 传true或false
有些时候的选项并不进行传值,而是传true或false
gcc -c foo.c // -c 就是一个flag,代表true只编译不链接。如果不写,则进行编译和链接。
#include <getopt.h> /* getopt */
#include <stdio.h> /* printf */
/* File scope flags, all default to 0 */
static int f_add;
static int f_append;
static int f_create;
static int f_delete;
static int f_verbose;
int main(int argc, char **argv)
{
int c;
while (1)
{
int option_index = 0;
static struct option long_options[] =
{
{"add", no_argument, &f_add, 1},
{"append", no_argument, &f_append, 1},
{"create", no_argument, &f_create, 1},
{"delete", no_argument, &f_delete, 1},
{"verbose", no_argument, &f_verbose, 1},
{NULL, 0, NULL, 0}
};
c = getopt_long(argc, argv, "-:", long_options, &option_index);
printf("the value of c : %d\n",c);
if (c == -1)
break;
switch (c)
{
case 1:
printf("non option argument '%s'\n", optarg);
break;
case '?':
printf("Unknown option %c\n", optopt);
break;
}
}
printf(" f_add: %i\n", f_add);
printf(" f_append: %i\n", f_append);
printf(" f_delete: %i\n", f_delete);
printf(" f_create: %i\n", f_create);
printf("f_verbose: %i\n", f_verbose);
return 0;
}
测试结果为:
Command line | Output |
---|---|
./a.out --verbose --create | f_add: 0 f_append: 0 f_delete: 0 f_create: 1 f_verbose: 1 |
./a.out --verbose --append --create --add --delete | f_add: 1 f_append: 1 f_delete: 1 f_create: 1 f_verbose: 1 |
./a.out --v --c --ap --ad --d | f_add: 1 f_append: 1 f_delete: 1 f_create: 1 f_verbose: 1 |
./a.out -v -c -d -a | Unknown option v Unknown option c Unknown option d Unknown option a f_add: 0 f_append: 0 f_delete: 0 f_create: 0 f_verbose: 0 |
如果flag为NULL,则这个 getopt_long函数返回 val
如果flag为指针,则将val放到flag指针中,这个getopt_long函数返回 0
5. 我的小代码
#include <stdio.h> /* for printf */
#include <stdlib.h> /* for exit */
#include <getopt.h>
int main(int argc, char *argv[])
{
int c;
int digit_optind = 0;
// 默认为0
static int f_flag;
while (1) {
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] = {
{"add", required_argument, 0, 'a'},
{"append", no_argument, 0, 'p'},
{"delete", required_argument, 0, 'd'},
{"verbose", no_argument, 0, 'v'},
{"create", required_argument, 0, 'c'},
{"file", optional_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
{"flag", no_argument, &f_flag, 1 },
{0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "-:a:pd:vc:f::h",long_options, &option_index);
//printf("the value of c : %d\n",c)
if (c == -1)
break;
switch (c)
{
case 0:
printf("%s (true of false),the flag value is %d\n", long_options[option_index].name,f_flag);
break;
case 1:
printf("non option argument '%s'\n", optarg);
break;
case 'a':
printf("option a or add with value '%s'\n", optarg);
break;
case 'p':
printf("option p or append\n");
break;
case 'd':
printf("option d or delete with value '%s'\n", optarg);
break;
case 'v':
printf("option v or verbose\n");
break;
case 'c':
printf("option c or create with value '%s'\n", optarg);
break;
case 'f':
printf("option f or file with value '%s'\n", optarg ? optarg : "NULL");
break;
case '?':
printf("Unknown option %c\n", optopt);
break;
case ':':
printf("Missing option for %c\n", optopt);
break;
default:
printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]);
printf("\t-a,--add add somethings(required argument)\n");
printf("\t-p,--append append somethings(no argument)\n");
printf("\t-d,--delete delete somethings(required argument)\n");
printf("\t-v,--verbose show the verbose(no argument)\n");
printf("\t-c,--create create somethings(required argument)\n");
printf("\t-f,--file add a file(required argument)\n");
printf("\t-h,--help help(no argument)\n");
printf("\t--flag flag 0 or 1(no argument)\n");
printf("\n");
exit(0);
}
}
exit(EXIT_SUCCESS);
}
这个代码可以输出帮助信息,以及 上述0、1、2、3、4等各种问题的结合版,可以参考,谢谢。
参考文档:
1. Example of Getopt (The GNU C Library)
2. man 3 getopt