前言:最近在学习面向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 */ optwhile ((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: 0f_append: 0f_delete: 0f_create: 1 f_verbose: 1 |
./a.out --verbose --append --create --add --delete | f_add: 1f_append: 1f_delete: 1f_create: 1 f_verbose: 1 |
./a.out --v --c --ap --ad --d | f_add: 1f_append: 1f_delete: 1f_create: 1 f_verbose: 1 |
./a.out -v -c -d -a | Unknown option v Unknown option c Unknown option d Unknown option af_add: 0f_append: 0f_delete: 0f_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;// 默认为0static 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
3.Mead's Guide To getopt