语言下解析命令行选项参数的函数---getopt

通常我们的命令行选项有两种存在:长选项短选项长选项使用--标识,而短选项使用-标识。

函数原型及其相关常量说明

头文件

#include <unistd.h>

原型

int getopt(int argc, char * const argv[], const char *optstring);

常量

extern char *optarg; //选项的参数指针
extern int optind;   //扫描选项时,标识下一个选项的index;全部扫描结束之后,标识第一个非选项参数的index。
extern int opterr;   //出现不可识别的选项时,将打印错误信息;将opterr赋值为0,则不打印错误信息。
extern int optopt;   //当命令行选项字符不存在或者缺少必要的参数时,将该选项存在optopt中,同时getopt函数返回`?`。

getopt传入参数说明

  • argc
    由main函数传入,参数个数。
  • argv
    由main函数传入,参数数组
  • optstring
    选项字符集合,形如:a:bc:d这种。

optstring说明
若选项后带参数,需在选项后加:,对应的参数值保存在optarg中。
ab:,指明应用程序支持-a-b两个选项,其中-a不带参数,而-b带参数。

./test -a -b param

总结如下:
1.单个字符,表示选项,
2.单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。
3 单个字符后跟两个冒号::,表示该选项后必须跟一个参数。参数必须紧跟在选项后不能以空格隔开(如:-efilename,-e为选项,filename为参数)。该参数的指针赋给optarg。(这个特性是GNU的扩展)。

扫描解析过程

即,getopt函数如何对选项及参数进行解析的过程。
getopt首先扫描argv[1]到argv[argc-1],并将选项及参数依次放到argv数组的最左边,非选项参数依次放到argv的最后边。

比如,我们的optstringab:c:de::执行命令如下:

./test file1 -a  -b -c code -d file2 -e file3

一共10个参数,对应如下:

0 1 2 3 4 5 6 7 8 9
./test file1 -a -b -c code -d file2 -e file3

在扫描过程中,optind是下一个选项的索引值,非选项参数将被跳过,同时optind增1。optind初始值为1

当扫描argv[1]时,为非选项参数,跳过,optind=2;
扫描到-a选项时, 下一个将要扫描的选项是-b,则optind更改为3;
扫描到-b选项时,后面有参数(会认为-c为选项b的参数),optind=5;
扫描到code非选项跳过optind=6;
扫描到-d选项,后面没有参数,optind=7;
扫描到file2非选项跳过optind=8;
扫描到-e后面本来应该有参数,optind=9但是有空格所以e的参数为空。

扫描过程如上,待扫描结束之后,argv数组排列如下:

0 1 2 3 4 5 6 7 8 9
./test -a -b -c -d -e file1 code file2 file3

可以看到上述,选项字符都依次排列到了最左边,而非选项参数都排列到了最右边;同时optind会指向非选项的第一个参数,如上面,optind将指向file1。

如果修改参数排列顺序为:

./test -a  -b -c code -d file2 -e file3 file1

扫描后的顺序为:

./test -a -b -c -d -e code file2 file3 file1

此时optind指向的参数为code

代码示例

代码如下:

#include <unistd.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
    int aflag=0, bflag=0, cflag=0;
    int ch;
    int i;
    printf("optind:%d,opterr:%d\n",optind,opterr);
    printf("--------------------------\n");
    while ((ch = getopt(argc, argv, "ab:c:de::")) != -1)
    {
        printf("optind: %d,argc:%d,argv[%d]:%s\n", optind,argc,optind,argv[optind]);
        printf("argv:");
        for(i=0; i<argc; i++){
            printf("%s ", argv[i]);
        }
        printf("\n");
        switch (ch) {
        case 'a':
            printf("HAVE option: -a\n\n");

            break;
        case 'b':
            printf("HAVE option: -b\n");

            printf("The argument of -b is %s\n\n", optarg);
            break;
        case 'c':
            printf("HAVE option: -c\n");
            printf("The argument of -c is %s\n\n", optarg);

            break;
    case 'd':
        printf("HAVE option: -d\n");
        break;
    case 'e':
        printf("HAVE option: -e\n");
        printf("The argument of -e is %s\n\n", optarg);
        break;

        case '?':
            printf("Unknown option: %c\n",(char)optopt);
            break;
        }
    }
    printf("----------------------------\n");
    printf("argv:");
    for(i=0; i<argc; i++){
        printf("%s ", argv[i]);
    }
    printf("\n");
    printf("optind=%d,argv[%d]=%s\n",optind,optind,argv[optind]);
}

执行结果如下:

参考:

最后修改:2019 年 05 月 18 日 11 : 06 AM