Linux下很多程序甚至那些具有图形用户界面(graphical user interface,GUI)的程序,都能接受和处理命令行选项。对于某些程序,这是与用户进行交互的主要手段。具有可靠的复杂命令行参数处理机制,会使得您的应用程序更好、更有用。getopt()是一个专门设计来减轻命令行处理负担的库函数。 1、命令行参数 命令行程序设计的首要任务是解析命令行参数,GUI派的程序员很少关心这个。这里,对参数采用了一种比较通俗的定义:命令行上除命令名之外的字符串。参数由多项构成,项与项之间用空白符彼此隔开。 参数进一步分为选项和操作数。选项用于修改程序的默认行为或为程序提供信息,比较老的约定是以短划线开头。选项后可以跟随一些参数,称为选项参数。剩下的就是操作数了。 2、POSIX约定
POSIX 表示可移植操作系统接口: Portable Operating System Interface,电气和电子工程师协会(Institute of Electrical and Electronics Engineers,IEEE)最初开发 POSIX 标准,是为了提高 UNIX 环境下应用程序的可移植性。然而,POSIX 并不局限于 UNIX。许多其它的操作系统,例如 DEC OpenVMS 和 Microsoft Windows NT,都支持 POSIX 标准。
char *optarg——当前选项参数字串(如果有)。 int optind——argv的当前索引值。当getopt()在while循环中使用时,循环结束后,剩下的字串视为操作数,在argv[optind]至argv[argc-1]中可以找到。 int opterr——这个变量非零时,getopt()函数为“无效选项”和“缺少参数选项,并输出其错误信息。
int optopt——当发现无效选项字符之时,getopt()函数或返回'?'字符,或返回':'字符,并且optopt包含了所发现的无效选项字符。
以下面的程序为例: 选项:
-n —— 显示“我的名字”。
-g —— 显示“我女朋友的名字”。
-l —— 带参数的选项.
清单2:
#include #include int main (int argc, char **argv) { int oc; /*选项字符 */ char *b_opt_arg; /*选项参数字串 */ while((oc = getopt(argc, argv, "ngl:")) != -1) { switch(oc) { case 'n': printf("My name is Lyong.\n"); break; case 'g': printf("Her name is Xxiong.\n"); break; case 'l': b_opt_arg = optarg; printf("Our love is %s\n", optarg); break; } } return 0; }
运行结果:
$ ./opt_parse_demo -n My name is Lyong. $ ./opt_parse_demo -g Her name is Xxiong. $ ./opt_parse_demo -l forever Our love is forever $ ./opt_parse_demo -ngl forever My name is Lyong. Her name is Xxiong. Our love is forever
#include #include int main (int argc, char **argv) { int oc; /*选项字符 */ char *b_opt_arg; /*选项参数字串 */ while((oc = getopt(argc, argv, "ngl:")) != -1) { switch(oc) { case 'n': printf("My name is Lyong.\n"); break; case 'g': printf("Her name is Xxiong.\n"); break; case 'l': b_opt_arg = optarg; printf("Our love is %s\n", optarg); break; case '?': printf("arguments error!\n"); break; } } return 0; }
输入一个错误的命令行,结果如下:
$ ./opt_parse_demo -l ./opt_parse_demo: option requires an argument -- l arguments error!
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()会进行线性搜索。但是,根据长名字来排序会使程序员读起来更容易。 以上所说的flag和val的用法看上去有点混乱,但它们很有实用价值,因此有必要搞透彻了。 大部分时候,程序员会根据getopt_long()发现的选项,在选项处理过程中要设置一些标记变量,譬如在使用getopt()时,经常做出如下的程序格式:
int do_name, do_gf_name, do_love; /*标记变量*/ char *b_opt_arg; while((c = getopt(argc, argv, ":ngl:")) != -1) { switch (c){ case 'n': do_name = 1; case 'g': do_gf_name = 1; break; break; case 'l': b_opt_arg = optarg; …… } }
while((c = getopt_long(argc, argv, ":l:", 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; }
测试结果如下:
$ ./long_opt_demo --name --gf_name --love forever My name is LYR. Her name is BX. Our love is forever! $ ./long_opt_demo -ng -l forever My name is LYR. Her name is BX. Our love is forever!
文章评论(0条评论)
登录后参与讨论