曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5164|回复: 2
打印 上一主题 下一主题

getopt

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2009-2-16 17:22:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
函数原型及相关变量
#include <unistd.h>
int getopt(int argc, char *const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
参数解释
char *optarg
        如果选项接受参数的话,那么它就是选项参数
int optind
        argv 的当前索引。当 while 循环检测结束时,剩下的操作数在 argv[optind] 至 argv[argc-1] 中能找到( 注意,'argv[argc] == NULL' )
int opterr
        当这个变量非零(默认非零)时,getopt() 函数为 ”无效选项“ 和 ”缺少选项参数“ 这两种错误情况输出它自己的错误消息
int optopt
         当发现无效字符的时候,getopt() 函数或者返回 ‘?' 字符,或者返回 ':' 字符,并且 optopt 包含了所发现的无效选项字符。


getopt() 函数也使用 main 中的两个参数 argc 和 argv 以及一个选项区别符字符串(option specifier string<optstring>)来告诉 getopt 程序都定义了什么哪些选项以及它们是否关联了值。

optstring 是一个简单的字符列表,每一个代表一个单字符选项。如果一个字符后面跟着一个冒号,那么它表明这个选项后面需要接着一个值。另外,在 bash 中 getopts 命令有着类似的功能。

如 getopt(argc, argv, "if:lr") 中,允许有 4 个简单的选项: -i, -l, -r, -f,其中 -f后面跟着冒号,所以在实际使用中, -f 后面要带着个值.

getopt 返回的结果是 argv 数组中的下一个选项字符(从程序名开始算起的下一个。也就是,每当找到一个有效的选项字母,就会返回这个字母)。重复调用 getopt 就会依次得到每一个选项。getopt 有如下的特性:

1、如果一个选项带有值,那这个 optarg 这个指针变量将指向这个值

示例代码
01 #include <stdio.h>
02 #include <unistd.h>
03
04 int main(int argc, char *argv[])
05 {
06         getopt(argc, argv, ":if:");
07
08         printf("%s\n", optarg);
09
10         return 0;
11 }
运行及打印结果
[root@localhost C]# ./getopt-2.exe -f write.c
write.c
:在 ":if:" 中有两个冒号,对这两个冒号的解释是:
如果 getopt() 中第三个参数的第一个字符是冒号,那么 getopt() 函数就会保持沉默,并根据错误情况返回不同的字符,如下:
“无效选项”
          getopt() 函数返回 '?',并且 optopt 包含了无效选项字符。
“缺少选项参数”
          getopt() 函数返回 ':'。(如果 optstring 的第一个字符不是冒号,那么 getopt() 函数返回 '?',使得这种情况不能与无效选项的情况区别开来。
因此,将 optstring 的第一个字符设置成冒号是个好主意,因为这样就可以将 “无效选项” 和 “缺少选项参数” 区别开来。但付出的代价是,getopt() 函数沉默了,如此一来,就迫使我们自己要给出出错信息---如用 fprintf(stderr, "%s: option '-%c' requires an argument\n", argv[0], optopt); 打印出错信息。例如以下代码:
c:write.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
        int oc;
        char *b_opt_arg;

        while ((oc = getopt(argc, argv, ":if:")) != -1) {
                switch (oc) {
                case 'i':
                        printf(" i arg\n");
                        break;
                case 'f':
                        printf("%s\n", optarg);
                        break;
                case ':':
                        fprintf(stderr, "%s: option '-%c' requires an argument\n", argv[0], optopt);
                        break;
                case '?':
                        fprintf(stderr, "%s: option '-%c' is invalid: ignored\n", argv[0], optopt);
                        break;
                }
        }

        exit(0);
}
两次错误输出
[root@localhost C]# ./write.exe -f
./write.exe: option '-f' requires an argument
[root@localhost C]# ./write.exe -l
./write.exe: option '-l' is invalid: ignored
2、当不再有选项可以处理时,getopt 返回 -1. 一个特殊的符号是 --,这会引起 getopt 停止对后面选项的扫描。
测试代码一
01 #include <stdio.h>
02 #include <unistd.h>
03
04 int main(int argc, char *argv[])
05 {
06         int opt;
07
08         opt = getopt(argc, argv, ":ijklmnf:");
09         printf("%d\n",opt);
10
11
12         opt = getopt(argc, argv, ":ijklmnf:");
13         printf("%d\n",opt);
14
15
16         opt = getopt(argc, argv, ":ijklmnf:");
17         printf("%d\n",opt);
18
19
20         return 0;
21 }
运行及其输出结果
[root@localhost C]# ./getopt-2.exe -i -k
105
107
-1
[root@localhost C]# ./getopt-2.exe -i -n
105
110
-1
由上可见,当处理完所有的选项若还想继续处理下一个时,opt 为 -1; 这里输出的整数指其实是参数的ASCII码

遇到 -- 时
01 #include <stdio.h>
02 #include <unistd.h>
03
04 int main(int argc, char *argv[])
05 {
06         int opt;
07
08         while( (opt = getopt(argc, argv, ":ijklmnf:")) != -1 ){
09
10         printf("%c\n",opt);
11         }
12
13         return 0;
14 }

测试运行输出
[root@localhost C]# ./write-2.exe -j -k -- -f write.c
j
k
[root@localhost C]# ./write-2.exe -j -- -k
j
说明
符合 POSIX 标准的 getopt() 函数一碰到不以 '-' 开始的命令行参数就停止寻找选项。GNU getopt() 是不一样的:它扫描整个命令行来寻找选项。当调用 GNU getopt() 函数处理命令行的时候,它重新排列 argv 的元素,这样当它重新排列完的时候,所有选项都移动到前面并且那些继续检查 argv[optind] 至 argv[argc-1] 中的剩余参数的代码仍正常工作。不管在什么情况下,碰到特殊参数 '--' 就结束选项的扫描。

3、如果遇到一个未知的选项,getopt 返回 ?,这个未知选项存储在外部变量 optopt 中
测试代码
01 #include <stdio.h>
02 #include <unistd.h>
03
04 int main(int argc, char *argv[])
05 {
06         int opt;
07
08         while( (opt = getopt(argc, argv, ":ijklmnf:")) != -1 ){
09
10         printf("%c\n",opt);
11         printf("%c\n",optopt);
12         }
13
14         return 0;
15 }
运行输出
[root@localhost C]# ./getopt-2.exe -z
?
z

4、如果选项要求一个值(如上代码中的 -f 参数),但在使用时没把值给出,getopt 一般返回 ? 号
在第一个字符的前面有冒号,那么如果需要给定值的参数后面没有给出值,那么返回冒号 :
测试代码和 3 中的一样,测试输出:
[root@localhost C]# ./getopt-2.exe -f
:
f

如果 3 中的代码参数 ":ijklmnf:" 这里去掉 i 签面的冒号 : ,那么输出:
[root@localhost C]# ./getopt-2.exe -f
./getopt-2.exe: option requires an argument -- f
?
f

外部变量 optind 是下一个要处理参数的索引值,getopt 使用它来记录 getopt 已经索引到了哪个值处。程序中一般很少设置到这个变量。如,getopt.exe -i -j 中,首先要处理的参数是 getopt.exe,下一个要处理的参数就是 -i,所以 -i 的索引值为 2 。
测试代码
01 #include <stdio.h>
02 #include <unistd.h>
03
04 int main(int argc, char *argv[])
05 {
06         int opt;
07
08         while( (opt = getopt(argc, argv, ":ijklmnf:")) != -1 ){
09
10         printf("%c,%d\n",opt,optind);
11
12         }
13
14         return 0;
15 }
运行与输出
[root@localhost C]# ./getopt-2.exe -i -j -m
i,2
j,3
m,4
当所有的选项都被测试都被处理完时, optind 表示在 argv 数组的末尾处(未处理的参数声明都一起放在数组的末尾)里还剩下多少的参数声明(arguments)
示例代码:
01 int main(int argc, char *argv[])
02 {
03         int opt;
04
05         while( (opt = getopt(argc, argv, ":ijklmnf:")) != -1 ){
06
07         printf("%c,%d\n",opt,optind);
08
09         }
10
11         for(; optind < argc; optind++){
12                 printf("%d\n");
13                 printf("remain in argv-array argument%d: %s\n", optind,argv[optind]);
14         }
15         return 0;
16 }
运行及输出:
[root@localhost C]# ./getopt-2.exe -i 'good' -k 'yes' -j 'ok' -l
i,2
k,4
j,6
l,8
5
remain in argv-array argument5: good
6
remain in argv-array argument6: yes
7
remain in argv-array argument7: ok

一些版本的 getopt 在遇到第一个非选项(non-option)参数时会听下来,并返回 -1,同时设定 optind 的值。其它的,如 Linux 提供的那些,可以处理在程序中任何地方出现的选项。注意,在这种情况下,getopt 重写 argv 数组,这样所有的非选项参数从 argv[optind] 开始连续的存放这些选项。对于 GNU 版本的 getopt,这个特性由 POSIXLY_COREECT 环境变量来控制.如果设置, getopt 将在第一个非选项参数处停下来.注意,POSIX 规格指出如果 opterr 变量非0, getopt 将会向 stderr 打印错误信息.

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
沙发
 楼主| 发表于 2009-2-17 22:21:54 | 只看该作者

getopt 应用示例

测试代码:
01 #include <stdio.h>
02 #include <unistd.h>
03 #include <stdlib.h>
04
05 int main(int argc, char *argv[])
06 {
07         int opt;
08
09         while((opt = getopt(argc, argv, ":if:lr")) != -1) {
10                 switch(opt) {
11                 case 'i':
12                 case 'l':
13                 case 'r':
14                         printf("option: %c\\n", opt);
15                         break;
16                 case 'f':
17                         printf("filename: %s\\n", optarg);
18                         break;
19
20                 case ':':
21                         printf("option needs a value\\n");
22                         break;
23
24                 case '?':
25                         printf("unknown option: %c\\n", optopt);
26                         break;
27                 }
28         }
29
30         for(; optind < argc; optind++)
31                 printf("argument: %s\\n", argv[optind]);
32         exit(0);
33 }

运行及输出:
[root@localhost C]# ./getopt.exe -i -lr 'hi there' -f write.c -q
option: i
option: l
option: r
filename: write.c
unknown option: q
argument: hi there

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
板凳
 楼主| 发表于 2009-4-13 23:29:50 | 只看该作者
最后,如果 optstring 中的选项字母后面有两个冒号,那么就允许这个选项拥有可选的选项参数!
如果这样的参数与选项在相同的 argv 元素中,那么就认为选项参数存在,否则就不存在。在选项参数不错你在的情况下,GNU getopt() 返回选项字母并将 optarg 设置为 NULL。例如,给出程序:

while((c = getopt(argc, argv, "ab::")) != -1)
如果命令行参数是 -bYANKEES,那么返回值是 'b',并且 optarg 设置成 "YANKEES";
如果命令参数是 -b 或者 '-b YANKEES' 返回值仍然是 'b',但是 optarg 设置为 NULL。后面这种情况 "YANKEES" 是分隔开的命令行参数。

测试代码
#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv)
{
        int c;
        while(( c = getopt(argc, argv, "ab::")) != -1){
                switch(c) {
                        case 'a':
                                printf("option: %c\\n", c);
                                break;
                        case 'b':
                                printf("option: %c\\n", c);
                                printf("argument: %s\\n", optarg);
                                break;
                }
        }

        return 0;
}
几种输出情况
[root@localhost C]# ./write-3.exe -b
option: b
argument: (null)
[root@localhost C]# ./write-3.exe -b YANKEES
option: b
argument: (null)
[root@localhost C]# ./write-3.exe '-b YANKEES'
option: b
argument:  YANKEES
[root@localhost C]# ./write-3.exe "-b YANKEES"
option: b
argument:  YANKEES
说明
在第二种输出情况中,如上面所讲,YANKEES 是被分隔开的命令行参数;
在第三,第四种输出情况中,由于单引号和双引号把 -b 和 YANKEES 一起括起来的关系,则 YANKEES 这样的参数与选项 b 被认为在相同的 argv 元素中,那么就认为选项参数存在,所以 optarg 的值为 YANKEES 。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-3 23:23 , Processed in 0.069800 second(s), 21 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表