本文讲解如何处理命令行传入的选项和参数
比如我们执行如下指令会输出file文件的前10行:
head file // 默认输出file的前10行
如果我们想要输出文件的前50行,就可以加选项"-n"和参数50
head -n 50 file
通过传入-n 50, head程序就知道我们想要得到是前50行。
在C/C++中,我们通过getopt()、getopt_long()以及getopt_long_only()函数来处理这些传入的选项参数。
getopt()
#include <unistd.h>
extern char* optarg
extern int optind
extern int opterr
extern int optopt
int getopt(int argc, char* const argv[], const char* optstring)
| |
| |getopt()中的argc, argv就是main()中的argc, argv
| |
int main(int argc, char* const argv[])
argc是传入的所有参数的数量
argv是传入的参数array
比如我们有一个编译为main的程序,当执行如下指令:
./main -t 100 -c 200 file
argc = 6 (包括./main, -t, 100, -c, 200, file)
argv就是“-t 100 -c 200 file”
除此之外还需要了解几个概念:
-
option element
以 ‘-’ 开始的选项
比如-t, -c就是option element,而100, 200, file不是(是’-‘而不是"-“或者”–")
t和c又称为option character
如果读取到了’-’,后面却没有对应的option character,getopt()会返回-1 -
optind
这个变量指向在argv中要读取的下一个character的位置
比如getopt()读取到了-t,它会将optind更新指向下一个可以读取到option element的地方(在这里就是-s)
这样,下次再次调用optget()的时候,getopt()就知道应该从哪里继续读取了
optind最终会停在第一个不是option element的地方(比如这里就是file) -
optarg
指向参数的指针
比如getopt()读取到了-t,那么optarg就会指向后面的参数’100’开始的位置 -
optstring
optstring代表合法的option character。
假如我们定义optstring = “a: b :c ::”,就代表,我们输入的选项可以有-a -b和-c
optstringt里面的冒号":“代表这个选项后面需要一个参数,那么当读取了-t后,optarg会自动指向参数开始的地方
两个冒号”::“代表选项可以有参数,也可以没有参数。
如果optstring以‘+’开头,如”+a: b: c::",那么一旦getopt()读取到一个非option的选项,就会立刻停止,不会继续处理argv了
如果optstring以’-'开头,如"-a: b: c::",那么即使读到非option选项,getopt()还是会继续处理argv,只是把这些非option选项当做一个特殊的option选项的参数。 -
optopt
假如getopt()读取到了一个不在optstring中的character,也就是读取到了一个不合法的option,它会输出error信息,并且将这个不合法的option character存到optopt中,然后返回一个’?’
return value
- 遇到的option是合法的:返回这个option character
- 遇到的option不合法:返回’?’
- 遇到的option缺参数:可能返回’:‘或者’?’ (取决于optstring的第一个character)
- 所有options都处理完毕:返回-1
getopt_long()
int getopt_long(int argc, char* const argv[], const char* optstring
const struct option* longopts, int* longindex);
getopt_long()和getopt()很像,不同的是它可以接受long option (’–'开始的option)。
./main -n 100 // getopt()只能处理'-'开始的短选项
./main --opt 100 // getopt_long()可以处理'--'开始的长选项
- optstring定义了合法的option character,意思就是,不包含long option
所以如果只有但是character的options,那么optstring应该设置为optstring = “” (不要设置为NULL)
-longopts
假设有多个long options,这些long options会被存在一个数组里
longopts就指向这个数组。
#include <getopt.h>
struct option{
const char* name; // long option的名字
int has_arg; // has_arg = 0 : 这个long option不需要参数
// has_arg = 1 : 这个long option需要参数
// has_arg = 2 : 这个long option参数可有可无
int *flag; // flag = NULL: getopt_long() returns val
// flag != NULL : getopt_long() returns 0
int val;
}
-longindex
如果longindex不为NULL的话,假设有一个数组存储了多个long options
当前long option是数组中的第3个options,那么longindex就指向这个3
return value:
- 处理成功short option:返回option character
- flag = NULL : 返回val
- flag != NULL: 返回0
- 遇到的option不合法:返回’?’
- 遇到的option缺参数:可能返回’:‘或者’?’ (取决于optstring的第一个character)
- 所有options都处理完毕:返回-1
getopt_long_only()
int getopt_long_only(int argc, char* const argv[], const char* optstring
const struct option* longopts, int* longindex);
在getopt_long_only()中,long option可以以’-‘或者’–‘开始。如果option以’-'开始却不是一个long option,那么会被转为一个short option来处理。
return value:
- 处理成功short option:返回option character
- flag = NULL : 返回val
- flag != NULL: 返回0
- 遇到的option不合法:返回’?’
- 遇到的option缺参数:可能返回’:‘或者’?’ (取决于optstring的第一个character)
- 所有options都处理完毕:返回-1
example
#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;
while (1) {
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] = {
{"add", required_argument, 0, 0 },
{"append", no_argument, 0, 0 },
{"delete", required_argument, 0, 0 },
{"verbose", no_argument, 0, 0 },
{"create", required_argument, 0, 'c'},
{"file", required_argument, 0, 0 },
{0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "abc:d:012",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
case '0':
case '1':
case '2':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf("option %c\n", c);
break;
case 'a':
printf("option a\n");
break;
case 'b':
printf("option b\n");
break;
case 'c':
printf("option c with value '%s'\n", optarg);
break;
case 'd':
printf("option d with value '%s'\n", optarg);
break;
case '?':
break;
default:
printf("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
exit(EXIT_SUCCESS);
}