getopt()和getopt32()

3 篇文章 0 订阅

getopt()和getopt32()这两个函数, 都是用来就是用来分析命令行参数的函数。

1. getopt()

在继续讨论getopt 之前,先要明确两个概念:选项(option) 和 选项参数(argument)。

如下例子:

gcc -g -lm foo.c -o foo 
-g 中的 g,-o 中的 o 还有 -lm 中的 l 就是选项,而 -lm 中的 m 就是 l 的选项参数,-o foo 中的 foo 就是 o 的选项参数。

因此,我们知道了选项有两种,一种是带选项参数的,另一中是不带选项参数的。

getopt() 函数声明在 unistd.h 头文件中,同时声明的还有几个全局变量, 如下:

#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.c */
#include <stdio.h>
#include <unistd.h> /* for getopt() and optind */

int main(int argc, char * argv[])
{
        int aflag=0, bflag=0, cflag=0;
        int ch;

        // opterr = 0;
        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\n");
                                cflag = 1;
                                break;
                        case '?':
                                printf("Unknown option: %c\n",(char)optopt);
                                break;
                }
        }
}
运行结果如下:

xxha@PAF4:~/git-server/sclib/c/getopt$ ./getopt -a -b hello -c
optind: 2
HAVE option: -a
optind: 4
HAVE option: -b
The argument of -b is hello
optind: 5
HAVE option: -c
变量opterr和optind都被初始化为1。如果想要略去命令行的前几个参数,可以在调用getopt()前将optind设成其他值。
如果不希望getopt()输出出错信息,将全域变量 opterr 设为 0 即可。
GNU Linux 中对 getopt 做了相应的扩展,提供了对长参数,例如 “--help” 的支持。主要是提供了 getopt_long 函数,
2. getopt32()
getopt32() 就是在busybox中对getopt()的扩展,其实意思都差不多,实现起来还是挺复杂的。

函数定义在:libbb/getopt32.c 中, 前面一堆函数使用说明,翻译成中文如下:

uint32_t getopt32(char **argv, const char *applet_opts,…)
命令行选项必须声明为类似const char *applet_opts的字符串形式, 例如:
flags = getopt32(argv, "rnug");

如果其中一个选项被找到了, 就有一个标志值(unsigned long类型)添加到返回值中。

标志值由字符在applet_opts种的位置决定, 例如在上例中:
flags = getopt32(argv, "rnug");

"r"将添加1 (0比特位)
"n"将添加2 (1比特位)
"u"将添加4 (2比特位)
"g"讲添加8 (3比特位)

等等, 你也可以通过位域方式查看返回值,每个选项就是其中一位.

一旦退出, 全局变量optind就被设置,因此如果你做argc -= optind; argv+= optind; argc就会等于剩下的非选项的参数个数,第一个放在argv[0],下一个放在argv[1]等等(选项和它们的参数在argv[optind]之前都会被移到argv[]中).

":"如果一个选项需要一个参数, 那就在applet_opts字符后面添加":"然后提供指向参数的指针. 例如:
  char *pointer_to_arg_for_a;
  char *pointer_to_arg_for_b;
  char *pointer_to_arg_for_c;
  char *pointer_to_arg_for_d;

  flags = getopt32(argv, "a:b:c:d:",
  &pointer_to_arg_for_a, &pointer_to_arg_for_b,
  &pointer_to_arg_for_c, &pointer_to_arg_for_d);
指针类型(char* 或 llist_t *)可以由"::"特殊分隔符控制,该分隔符由外部字符串opt_complementary设置(详细信息请看下面) 

"::" 如果选项有一个可选参数, 那就在applet_opts字符后面添加一个"::"并提供一个存储参数的指针. 注意可选参数必需紧跟着选项: -oparam而不是-o param.

"+" 如果applet_opts字符串第一个字符是加号, 那就argv数组中一旦遇上非选项字符就马上停止选项处理. 对于像env那样的applet就不会处理参数为子程序了: env -i ls -d /
这里我们希望env仅仅处理'-i'不是'-d'.

const char *applet_long_options
该结构体允许你定义长选项:
static const char applet_longopts[] ALIGN1 =
 //"name" has_arg val
 "verbose" No_argument "v";
 applet_long_options = applet_longopts;

结构体的最后一个成员(val)通常在applet_opts里面设置用来匹配短选项. 如果在applet_opts里面没有匹配到, 如是:
– 短选项的下一个位置的比特数
– 如果has_arg不是"No_argument", 也可以使用ptr作为参数
– opt_complementary也可以影响到它.

注意: 一个好的applet可以让长参数可配置,通过配置处理而不是必需的特征. 当前标准命名配置选项为CONFIG_FEATURE_<applet>_LONG_OPTIONS.

const char *opt_complementary
":" 冒号用来分隔两个或多个字符并/或字符组以及特殊字符(表示要检查一些状态)

"abc" 如果指定了两个或多个字符组, 第一个字符就是主选项,其余的字符是副选项。 如果找到了主选项, 他们的标志就出现了即使没有在命令行中指定他们. 例如:

opt_complementary = "abc";
flags = getopt32(argv, "abcd");

如果getopt()找到命令行中的"-a", getopt32的返回值就好比找到了"-a -b -c".

"ww" 调整有计数器关联来指示选项的发生次数的双选项. 例如ps applet的需要:
 如果w给定一次, GNU ps设置宽度为132,
 如果w给定的多于一次, 就是"无限制"

 int w_counter = 0; //必需初始化
 opt_complementary = "ww";
 getopt32(argv, "w", &w_counter);
 if (w_counter)
  width = (w_counter == 1) ? 132 : INT_MAX;
 else
  get_terminal_width(…&width…);

 w_counter是一个指向整数的指针, 它得在所有选项参数沉下去之后传给getopt32().

 例如: 接受多个-v来表示冗长级别和每一个-b optarg级别,添加optarg到my_b. 最后, 如果给定了b就关闭c或者反过来:
 llist_t *my_b = NULL;
 int verbose_level = 0;
 opt_complementary = "vv:b::b-c:c-b";
 f = getopt32(argv, "vb:c", &my_b, &verbose_level);
 if (f & 2) //-c在-b后面, 取消设置-b标志
  while (my_b) dosomething_with(llist_pop(&my_b));
 if (my_b) //但是如果指定了-b就存储llist
  free_llist(my_b);
 if (verbose_level) printf("verbose level is %dn", verbose_level);

特殊字符:
"-" opt_complementary组中的起始字符是横线强制要求所有参数作为选项来看待,尽管它们没有横线打头. 这种情况下下一个字符不能是数字(0-9), 使用':'或行结束符. 例如:
opt_complementary = "-:w-x:x-w";
getopt32(argv, "wx");
允许不适用横线而给定所有参数(./program w x), 就像带有横线一样(./program -x).
NB: getopt32()会泄露一小部分内存如果你使用这个项. 如果有递归调用getopt32()的可能就不要使用.

"–" opt_complementary开始的双横线表示argv[1]字符串应该总是作为选项来看待, 尽管不是以"-"做前缀. 这在诸如"ar"和"tar"的applet中有特别语义:
tar xvf foo.tar
NB: 如果你使用这个项,getopt32()将会泄露一小部分内存. 如果有递归调用getopt32()的可能就不要使用.

"-N" opt_complementary组的起始横线紧跟一个数字(0-9)意味着至少要在命令行里面出现N个非选项的参数.

"=N" opt_complementary起始的等号符紧跟打个数字(0-9)意味着要在命令行里出现恰好N个非选项参数.



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值