本文内容大部分翻译自Linux Man Page
用于学习如何解析命令行参数,其中讲解了getopt、getopt_long、getopt_long_only等函数的用法和区别。对下文中遇到的词汇做一下约定:
比如在终端输入:find /usr -name “*.txt”
选项:-name
参数:/usr、”*.txt”
选项字符:n
选项元素:-name
argv元素:find、/usr、-name、”*.txt”
#include
int getopt(int argc, char * const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
#include
int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
int getopt_long_only(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
getopt()
函数用来解析命令行参数。他的参数argc
和argv
分别是main
函数传进来的参数个数和参数列表。如果argv
中的元素以’-‘或’–’开头,则该元素是一个选项元素。在这个元素’-‘后面的字符是选项字符。如果getopt()
被反复调用,若执行成功,则会返回每个argv
中的选项元素的选项字符
optind
变量是个全局变量,表示在argv
中将要处理的下个元素的下标。一开始初始化这个值为1。如果需要的话,调用者可以重置它为1,比如在同一个程序中想再重新扫描这个argv
,或者处理一个新的参数列表。
如果getopt()
发现了另一个选项字符,它会返回这个字符,且更新optind
变量和nextchar
变量以便于下次调用getopt()
函数时可以继续处理下一个选项字符或argv元素。
如果没有更多的选项字符,getopt()
会返回-1。且optind
的值设置为argv
中第一个非选项的argv元素。
optstring
是一个包含了合法选项字符的字符串。如果这个字符后面紧跟一个冒号,则说明这个选项需要一个参数,这个参数可以紧跟在这个选项字符的后面,也可以是下一个argv元素,当optstring
为”d:”,且命令行中可以传入”-dabc”,则optarg
的值为指向”abc”的指针;如果传入的是”-d abc”,则optarg
指向下个argv元素,即”abc”元素。两个冒号意味着可以携带一个可选的参数。如果在这个选项字符后紧接着参数(“-dabc”),则optarg
会指向这个参数(“abc”),否则optarg
会被设置为0。(使用双冒号后,参数必须紧跟在选项字符后面)
默认情况下,getopt()
在扫描argv
的内容同时会对它进行重新排序,这样可以使得非选项元素都放在后面。还有其他两种模式,当optstring
第一个字符为’+’或环境变量POSIXLY_CORRECT被设置,则getopt()
在扫描argv
时候一遇到非选项元素时候会停止解析处理(getopt()
立即返回-1)。如果optstring
第一个字符为’-‘,每个非选项元素会被当做字符值为1(即ASCII码为1)的字符选项的参数,也就是说getopt()
返回1。这种模式主要是提供给需要关心选项和参数的顺序的调用者。如果指定了”–”选项,会终止getopt()
的选项处理(不管何种扫描模式),也就是说一律把”–”后面的argv元素当做参数来处理,即使有元素带’-‘。
当getopt()
函数遇到一个不认识的选项字符(没有在optstring
中出现),它会把错误信息打印在stderr中,并且把字符存在optopt
中,然后getopt()
会返回’?’。如果你不想打印它打印错误信息,可以设置opterr
为0。
当getopt()
函数遇到一个optstirng
中没有的字符,或者检测到某个选项缺少参数,则会返回一个’?’,同时设置optopt
的值为这个真实遇到的字符。如果optstring
的第一个字符(或者在’+’、’-‘后第一个字符)是’:’,则getopt()
在遇到缺少参数的选项时会返回’:’来代替’?’。如果检测到一个错误,且optstring
的第一个字符不是一个冒号,且opterr
的值为非零,getopt()
会打印错误信息。
getopt_long()
和getopt()
除了支持长选项(以”–”开头)外,其他都一样。(如果程序只接受长选项,optstring
应该被指定为空字符串(“”))。长选项可以在保证唯一性的情况下可以简写。一个长选项可以这样携带一个参数:–arg=param或者–arg param。
longopts
是一个指向struct option
数组的第一个元素的指针,struct option
(在
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
结构体option
各个字段的意思如下:
name
长选项的名字
has_arg
no_argument(或0):选项不携带参数;required_argument(或1):选项需要参数;optional_argument(或2):选项携带可选参数
flag
指定该长选项的返回值。如果flag是NULL,getopt_long
会返回val。(比如,调用者可以设置val为短选项字符)否则,getopt_long
会返回0,且flag指向的值设置为val的值,前提是该选项成功找到了。
val
当做返回值,或把值加载进flag所指的内存中。
longopts
指向的数组的最后一个元素值都设置为0。
如果longindex
不是NULL,它指向getopt_long()
获得的长选项在longopts
的下标。
getopt_long_only()
与getopt_long()
相似,不同的是getopt_long()
会把’-‘和”–”都当做一个长选项处理。而getopt_long_only()
会把一个以’-‘开头(不是”–”)的选项当做短选项处理。
如果成功找到了选项,getopt()
会返回选项字符。如果所有的命令行都已经解析完了,getopt()
会返回-1。如果getopt()
遇到一个optstring
没有的选项字符,则会返回’?’。如果遇到一个缺少参数的选项字符,返回值就要取决于optstring
的第一个字符了:如果是’:’,则返回’:’,否则返回’?’。
POSIXLY_CORRECT
如果该环境变量被设置,选项处理遇到非选项参数会立马停止(即getopt()等方法会立马返回-1)。
一个程序可以解析多个命令行参数数组,或者可以多次解析同一个命令行参数数组,且如果想在多个解析处理之间使用optstring
开头的’+’、’-‘,或改变POSIXLY_CORRECT环境变量的值,必须通过设置optind
为0来重新初始getopt()
,而不是设置为1。
下面的例子使用getopt()
来处理两个选项:-n,不携带任何参数;-t val,它携带一个参数
#include
#include
#include
int
main(int argc, char *argv[])
{
int flags, opt;
int nsecs, tfnd;
nsecs = 0;
tfnd = 0;
flags = 0;
while ((opt = getopt(argc, argv, "nt:")) != -1) {
switch (opt) {
case 'n':
flags = 1;
break;
case 't':
nsecs = atoi(optarg);
tfnd = 1;
break;
default: /* '?' */
fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n", argv[0]);
exit(EXIT_FAILURE);
}
}
printf("flags=%d; tfnd=%d; optind=%d\n", flags, tfnd, optind);
if (optind >= argc) {
fprintf(stderr, "Expected argument after options\n");
exit(EXIT_FAILURE);
}
printf("name argument = %s\n", argv[optind]);
/* Other code omitted */
exit(EXIT_SUCCESS);
}
下面的例子使用了getopt_long()
的大多数特性。
#include /* for printf */
#include /* for exit */
#include
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);
}