参考:
http://blog.csdn.net/zhangyang0402/article/details/5671410
http://www.cnblogs.com/gnuhpc/archive/2012/12/07/2807061.html
http://www.jb51.net/article/41462.htm
http://biancheng.dnbcw.info/c/236603.html
命令行工具下的参数选项有两种,长选项和短选项。短选项以-开头,后面跟单个字母;长选项以--开头,后面可跟多个字母。
功能:解析命令行短选项参数
函数原型:
#include <getopt.h>
int getopt(int argc, char * const argv[], const char *optstring);
几个外部变量
extern char *optarg;
extern int optind, opterr, optopt;
optarg:若短选项后有参数,则optarg指向该参数
optind:扫描选项时,标识下一个选项的索引;扫描结束后,标识第一个非选项参数索引
opterr:出现不可识别的选项时,getopt将打印错误信息。将opterr设为0,可不打印错误信息。
optopt:存放不可识别的选项至optopt
1. 参数
argc:参数的个数(main)
argv:参数数组(main)
optstring:短选项字符集合,如 -i -n中的i,n
若选项后面有参数,则选项字符后加:, 对应的参数值保存在外部变量optarg中
如optstring 为"i:a",则表示程序支持两个短选项 -i arg和-a, -i后面须有参数值
当执行./a.out -i filename -a时,optarg指针就指向filename
2. 解析过程
getopt首先扫描argv[1]到argv[argc-1],并将选项及参数依次放到argv数组的最左边,非选项参数依次放到argv的最后边
即该函数会改变argv的排列顺序。
如执行程序为:
0 1 2 3 4 5 6 7 8 9
$ ./mygetopt file1 -i infile -a -o outfile -v -h file2
扫描过程中,optind是下一个选项的索引(如-i、-a、-o、-v), 非选项参数将跳过,同时optind增1。optind初始值为1。当扫描argv[1]时,为非选项参数,跳过,optind=2;扫描到-i选项时,后面有参数,下一个将要扫描的选项是-a,则optind更改为4;扫描到-a选项时,下一个选项是-o,optind=5;扫描到-o选项时,后面有参数,下一个选项是-v,optind=7;扫描到-v选项时,下一个选项是-h,optind=8;扫描到-h选项时,optind=9
扫描结束后,getopt会将argv数组修改成下面的形式
0 1 2 3 4 5 6 7 8 9
$./mygetopt -i infile -a -o outfile -v -h file1 file2
同时,optind会指向非选项的第一个参数,如上面,optind将指向file1
3. 返回值
若getopt找到短选项字符,则返回该选项字符;
若出现不能接受的选项字符或丢失选项参数,则返回?,同时optopt将被设置成相应选项字符;
则后面没有选项字符,则返回-1
4. 测试
mygetopt.c
#include<stdio.h> #include <getopt.h> void usage(const char *p); int main(int argc, char *argv[]) { int ch=0; opterr=0; // prevent error information to print for unrecognized options while( (ch=getopt(argc, argv, "i:ao:vh") ) != -1 ) { switch(ch) { case 'i': printf("option i: %s\n", optarg); printf("optind=%d\n\n", optind); break; case 'a': printf("option a :%c\n", ch); printf("optind=%d\n\n", optind); break; case 'o': printf("option o: %s\n", optarg); printf("optind=%d\n\n", optind); break; case 'v': printf("option v: %c\n", ch); printf("optind=%d\n\n", optind); break; case 'h': usage(argv[0]); printf("optind=%d\n\n", optind); break; default: printf("unrecognized option: %c\n", optopt); usage(argv[0]); } } printf("optind = %d\n", optind); if ( optind < argc ) { printf("\nnon-option arguments below:\n"); while( optind < argc ) { printf("%s\n", argv[optind++]); } } for(ch=0; ch<argc; ch++) { printf("%s ",argv[ch]); } printf("\n"); return 0; } void usage(const char *p) { printf("Usage: %s [-i infile] [-a] [-o outfile] [-v] [-h] [file]\n", p); }
执行结果:
$ ./mygetopt file1 file2 -i infile -a baidu sina -o outfile -v renmin google -h bluestar file2
pengdl@debian:~/test/c$ ./a.out file1 file2 -i infile -a baidu sina -o outfile -v renmin google -h bluestar file2 option i: infile optind=5 option a :a optind=6 option o: outfile optind=10 option v: v optind=11 Usage: ./a.out [-i infile] [-a] [-o outfile] [-v] [-h] [file] optind=14 optind = 8 non-option arguments below: file1 file2 baidu sina renmin google bluestar file2 ./a.out -i infile -a -o outfile -v -h file1 file2 baidu sina renmin google bluestar file2 pengdl@debian:~/test/c$
=================================================================
getopt被用来解析命令行选项参数。而getopt_long支持长选项的命令行解析,其声明如下:
int getopt_long(int argc, char * const argv[],const char *optstring, const struct option *longopts,int *longindex);
函数中的argc和argv通常直接从main()的两个参数传递而来。optsting是选项参数组成的字符串;
optstring是一个字符串,表示可以接受的参数。例如,"a:b:cd",表示可以接受的参数是a,b,c,d,其中,a和b参数后面跟有更多的参数值。
longopts是一个结构体数组,option结构称为长选项表,其声明如下:
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
结构中的元素解释如下:
const char *name:选项名,前面没有短横线。譬如"help"、"verbose"之类。
int has_arg:描述长选项是否有选项参数,如果有,是哪种类型的参数,其值见下表:
符号常量 数值 含义
no_argument 0 选项没有参数
required_argument 1 选项需要参数
optional_argument 2 选项参数是可选的
int *flag:如果该指针为NULL,那么getopt_long返回val字段的值;如果该指针不为NULL,那么会使得它所指向的结构填入val字段的值,同时getopt_long返回0;
int val:如果flag是NULL,那么val通常是个字符常量,如果短选项和长选项一致,那么该字符就应该与optstring中出现的这个选项的参数相同;
longindex参数一般赋为NULL即可;如果没有设置为NULL,那么它就指向一个变量,这个变量会被赋值为寻找到的长选项在longopts中的索引值,这可以用于错误诊断。
对于options类型参数可以有两种方式:
1)短选项(short options):顾名思义,就是短小参数。它们通常包含一个连字号和一个字母(大写或小写字母)。例如:-s,-h等。
2)长选项(long options):长选项,包含了两个连字号和一些大小写字母组成的单词。例如,--size,--help等。
每次调用getopt_long,它会解析一个符号,返回相应的短选项字符,如果解析完毕返回-1。所以需要使用一个循环来处理所有的参数,而相应的循环 里会使用switch语句进行选择。如果getopt_long遇到一个无效的选项字符,它会打印一个错误消息并且返回'?',很多程序会打印出帮助信息 并且中止运行;当getopt_long解析到一个长选项并且发现后面没有参数则返回':',表示缺乏参数。当处理一个参数时,全局变量optarg指向 下一个要处理的变量。当getopt_long处理完所有的选项后,全局变量optind指向第一个未知的选项索引。
#include <stdio.h> #include <stdlib.h> #include <getopt.h>
int main() { char *argv[] = {"getopt", "-h", "--version", "-c forever"}; int argc = sizeof(argv)/sizeof(argv[0]); int c; const struct option long_options[] = { { "help", 0, NULL, 'h' }, { "acat", 1, NULL, 'c' }, { "version", 0, NULL, 'v' }, { NULL, 0, NULL, 0} }; while (1) { int option_index = 10; c = getopt_long(argc, argv, "hvc:", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': printf("option h \n"); break; case 'c': printf("option c with value '%s'\n", optarg); break; case 'v': printf("option v %s\n", long_options[option_index].name); break; default: printf("?? getopt returned character code 0%o ??\n", c); break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } exit(EXIT_SUCCESS); }
输出结果:
option h
option v version
option c with value ' forever'
=================================================================
每一天你都在使用大量的命令行程序,是不是感觉那些命令行参数用起来比较方便,他们都是使用getopt来实现的。
在Linux下使用getopt写程序是一种比较cool的事情,下面来简单的介绍一下getopt的使用。
#include <unistd.h> extern char *optarg; extern int optind; extern int optopt; extern int opterr; extern int optreset; int getopt(int argc, char * const *argv, const char *optstring);
直接看一个例子:
/* getopt.c */ #include <unistd.h> #include <stdio.h> int main(int argc, char * argv[]) { int aflag=0, bflag=0, cflag=0; int ch; while ((ch = getopt(argc, argv, "ab:c")) != -1) { printf("optind: %d\n", optind); switch (ch) { case 'a': printf("HAVE option: -a\n"); aflag = 1; break; case 'b': printf("HAVE option: -b\n"); bflag = 1; printf("The argument of -b is %s\n", optarg); break; case 'c': printf("HAVE option: -c"); cflag = 1; break; case '?': printf("Unknown option: %c\n",(char)optopt); break; } } }
wangyao@fisherman:~/Desktop/Advanced Linux Programming/ALP-listings/Trainning$ ./getopt -a -d -b foo optind: 2 HAVE option: -a ./getopt: invalid option -- d optind: 3 Unknown option: d optind: 5 HAVE option: -b The argument of -b is foo wangyao@fisherman:~/Desktop/Advanced Linux Programming/ALP-listings/Trainning$ ./getopt -a -- -c -b foo optind: 2 HAVE option: -a
#include <stdio.h> #include <getopt.h> int do_name, do_gf_name; char *l_opt_arg; static const char *shortopts = "l:ng"; struct option longopts[] = { {"name", no_argument, NULL, 'n'}, {"gf_name", no_argument, NULL, 'g'}, {"love", required_argument, NULL, 'l'}, {0, 0, 0, 0}, }; int main (int argc, char *argv[]) { int c; while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) { switch (c) { case 'n': printf ("My name is LYR.\n"); break; case 'g': printf ("Her name is BX.\n"); break; case 'l': l_opt_arg = optarg; printf ("Our love is %s!\n", l_opt_arg); break; } } return 0; }
wangyao@fisherman:~/Desktop/Advanced Linux Programming/ALP-listings/Trainning$ ./getopt_long --name My name is LYR. wangyao@fisherman:~/Desktop/Advanced Linux Programming/ALP-listings/Trainning$ ./getopt_long -n My name is LYR. wangyao@fisherman:~/Desktop/Advanced Linux Programming/ALP-listings/Trainning$ ./getopt_long -l me Our love is me! wangyao@fisherman:~/Desktop/Advanced Linux Programming/ALP-listings/Trainning$ ./getopt_long --love me Our love is me! wangyao@fisherman:~/Desktop/Advanced Linux Programming/ALP-listings/Trainning$
=== Reference ===
=================================================================
1.getopt
#include <unistd.h>
extern char *optarg;
extern int optind;
extern int optopt;
extern int opterr;
extern int optreset;
int getopt(int argc, char * const *argv, const char *optstring);
getopt()每调用一次返回一个选项。 argc 和 argv 很显然就是 main 函数的两个参数。
字符串 optstring 可以包含下列元素:单个字符,字符后面接一个冒号说明后面跟随一个选项参数,字符后面接两个冒号说明后面跟随一个可有可无的选项参数。例如,一个选项字符 "x" 表示选项 "-x" ,选项字符 "x:" 表示选项和其参数 "-x argument",选项字符 "x::" 表示选项 x 的参数是可选的(“::” 是 GNU 增加的,不一定在所有的UNIX 系统下都可以使用)。
getopt()的返回后,如果有选项参数的话 optarg 指向选项参数,并且变量 optind 包含下一个 argv 参数作为对 getopt() 下一次调用的索引。变量 optopt 保存最后一个由 getopt() 返回的已知的选项。
当参数列已经到结尾时getopt()函数返回-1,当遇到一个未知的选项时 getopt 返回'?'。参数列中选项的解释可能会被'--'取消,由于它引起 getopt()给参数处理发送结束信号并返回-1。
很多时候,我们不希望输出任何错误信息,或更希望输出自己定义的错误信息。可以采用以下两种方法来更改getopt()函数的出错信息输出行为:
在调用getopt()之前,将opterr设置为0,这样就可以在getopt()函数发现错误的时候强制它不输出任何消息。
如果optstring参数的第一个字符是冒号,那么getopt()函数就会保持沉默,并根据错误情况返回不同字符,如下:
“无效选项” ―― getopt()返回'?',并且optopt包含了无效选项字符(这是正常的行为)。
“缺少选项参数” ―― getopt()返回':',如果optstring的第一个字符不是冒号,那么getopt()返回'?',这会使得这种情况不能与无效选项的情况区分开。
/* getopt.c */ #include <unistd.h> #include <stdio.h> int main(int argc, char * argv[]) { int aflag=0, bflag=0, cflag=0; int ch; while ((ch = getopt(argc, argv, "ab:c")) != -1) { printf("optind: %d/n", optind); switch (ch) { case 'a': printf("HAVE option: -a/n"); aflag = 1; break; case 'b': printf("HAVE option: -b/n"); bflag = 1; printf("The argument of -b is %s/n", optarg); break; case 'c': printf("HAVE option: -c"); cflag = 1; break; case '?': printf("Unknown option: %c/n",(char)optopt); break; } } }
2.getopt_long
int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
其中我们使用了一个结构体struct options的数组,struct options longopt[].
struct options的定义如下:
struct option{
const char *name;
int has_arg;
int *flag;
int val;
};
对结构中的各元素解释如下:
const char *name
这是选项名,前面没有短横线。譬如"help"、"verbose"之类。
int has_arg
描述了选项是否有选项参数。如果有,是哪种类型的参数,此时,它的值一定是下表中的一个。
符号常量 数值 含义
no_argument 0 选项没有参数
required_argument 1 选项需要参数
optional_argument 2 选项参数可选
int *flag
如果这个指针为NULL,那么 getopt_long()返回该结构val字段中的数值。如果该指针不为NULL,getopt_long()会使得它所指向的变量中填入val字段中的数值,并且getopt_long()返回0。如果flag不是NULL,但未发现长选项,那么它所指向的变量的数值不变。
int val
这个值是发现了长选项时的返回值,或者flag不是NULL时载入*flag中的值。典型情况下,若flag不是NULL,那么val是个真/假值,譬如 1或0;另一方面,如果flag是NULL,那么 val通常是字符常量,若长选项与短选项一致,那么该字符常量应该与optstring中出现的这个选项的参数相同。
每个长选项在长选项表中都有一个单独条目,该条目里需要填入正确的数值。数组中最后的元素的值应该全是0。数组不需要排序,getopt_long()会进行线性搜索。但是,根据长名字来排序会使程序员读起来更容易。
#include <stdio.h> #include <getopt.h> int do_name, do_gf_name; char *l_opt_arg; static const char *shortopts = "l:ng"; struct option longopts[] = { {"name", no_argument, NULL, 'n'}, {"gf_name", no_argument, NULL, 'g'}, {"love", required_argument, NULL, 'l'}, {0, 0, 0, 0}, }; int main (int argc, char *argv[]) { int c; while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) { switch (c) { case 'n': printf ("My name is LYR./n"); break; case 'g': printf ("Her name is BX./n"); break; case 'l': l_opt_arg = optarg; printf ("Our love is %s!/n", l_opt_arg); break; } } return 0; }
具体案例: