zoukankan      html  css  js  c++  java
  • Linux下getopt()函数的简单使用

    摘自:https://www.cnblogs.com/qingergege/p/5914218.html

    更多请参考:https://blog.csdn.net/huangxiaohu_coder/article/details/7475156

    最近在弄Linux C编程,本科的时候没好好学啊,希望学弟学妹们引以为鉴。

    好了,虽然啰嗦了点,但确实是忠告。步入正题:

    我们的主角----getopt()函数。

    英雄不问出处,getopt()函数的出处就是unistd.h头文件(哈哈),写代码的时候千万不要忘记把他老人家include上。

    再来看一下这家伙的原型(不是六耳猕猴):

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

    前两个参数大家不会陌生,没错,就是老大main函数的两个参数!老大传进来的参数自然要有人接着!

    第三个参数是个字符串,看名字,我们可以叫他选项字符串(后面会说明)

    返回值为int类型,我们都知道char类型是可以转换成int类型的,每个字符都有他所对应的整型值,其实这个返回值返回的就是一个字符,什么字符呢,叫选项字符(姑且这么叫吧,后面会进一步说明)

    简单了解了出身和原型,下面我们看看这家伙到底有什么本事吧!

    (⊙o⊙)…在此之前还要介绍他的几个兄弟~~~~呃呃呃

    小弟1、extern char* optarg;

    小弟2、extern int optind;

    小弟3、extern int opterr;

    小弟4、extern int optopt;

    队形排的不错。小弟1是用来保存选项的参数的(先混个脸熟,后面有例子);小弟2用来记录下一个检索位置;小弟3表示的是是否将错误信息输出到stderr,为0时表示不输出,小弟4表示不在选项字符串optstring中的选项(有点乱哈,后面会有例子)

    开始逐渐解释上面遗留的问题。

    问题1:选项到底是个什么鬼?

    在linux下大家都用过这样一条指令吧:gcc helloworld.c -o helloworld.out; 这条指令中的-o就是命令行的选项,而后面的helloworld.out就是-o选项所携带的参数。当然熟悉shell指令的人都知道(虽然我并不熟悉),有些选项是不用带参数的,而这样不带参数的选项可以写在一起(这一点在后面的例子中会用到,希望理解),比如说有两个选项-c和-d,这两个选项都不带参数(而且明显是好基友),那么他们是可以写在一起,写成-cd的。实际的例子:当我们删除一个文件夹时可以使用指令 rm 目录名 -rf,本来-r表示递归删除,就是删除文件夹中所有的东西,-f表示不提示就立刻删除,他们两个都不带参数,这时他们就可以写在一起。

    问题2:选项字符串又是何方神圣?

    还是看个例子吧

    "a:b:cd::e",这就是一个选项字符串。对应到命令行就是-a ,-b ,-c ,-d, -e 。冒号又是什么呢? 冒号表示参数,一个冒号就表示这个选项后面必须带有参数(没有带参数会报错哦),但是这个参数可以和选项连在一起写,也可以用空格隔开,比如-a123 和-a   123(中间有空格) 都表示123是-a的参数;两个冒号的就表示这个选项的参数是可选的,即可以有参数,也可以没有参数,但要注意有参数时,参数与选项之间不能有空格(有空格会报错的哦),这一点和一个冒号时是有区别的。

    好了,先给个代码,然后再解释吧。

    #include <unistd.h>
    #include <stdio.h>
    int main(int argc, char * argv[])
    {
        
        int ch;
        printf("
    
    ");
        printf("optind:%d,opterr:%d
    ",optind,opterr);
        printf("--------------------------
    ");
           while ((ch = getopt(argc, argv, "ab:c:de::")) != -1)
           {
            printf("optind: %d
    ", optind);
               switch (ch) 
            {
                   case 'a':
                           printf("HAVE option: -a
    
    ");   
                           break;
                   case 'b':
                           printf("HAVE option: -b
    "); 
                           printf("The argument of -b is %s
    
    ", optarg);
                           break;
                   case 'c':
                           printf("HAVE option: -c
    ");
                           printf("The argument of -c is %s
    
    ", optarg);
                           break;
                   case 'd':
                       printf("HAVE option: -d
    ");
                         break;
                  case 'e':
                        printf("HAVE option: -e
    ");
                        printf("The argument of -e is %s
    
    ", optarg);
                      break;
                  case '?':
                           printf("Unknown option: %c
    ",(char)optopt);
                           break;
                   }
           }
    
    
    }
     
    编译后命令行执行:# ./main -b "qing er"
    
    输出结果为:
    
    optind:1,opterr:1
    --------------------------
    optind: 3
    HAVE option: -b
    The argument of -b is qing er
    
     
    
    我们可以看到:optind和opterr的初始值都为1,前面提到过opterr非零表示产生的错误要输出到stderr上。那么optind的初值为什么是1呢?
    
    这就要涉及到main函数的那两个参数了,argc表示参数的个数,argv[]表示每个参数字符串,对于上面的输出argc就为3,argv[]分别为: ./main 和 -b 和"qing er" ,实际上真正的参数是用第二个-b 开始,也就是argv[1],所以optind的初始值为1;
    
    当执行getopt()函数时,会依次扫描每一个命令行参数(从下标1开始),第一个-b,是一个选项,而且这个选项在选项字符串optstring中有,我们看到b后面有冒号,也就是b后面必须带有参数,而"qing er"就是他的参数。所以这个命令行是符合要求的。至于执行后optind为什么是3,这是因为optind是下一次进行选项搜索的开始索引,也是说下一次getopt()函数要从argv[3]开始搜索。当然,这个例子argv[3]已经没有了,此时getopt()函数就会返回-1
    再看一个输入:
    
     ./main -b "qing er" -c1234
    
    输出结果为:
    
    optind:1,opterr:1
    --------------------------
    optind: 3
    HAVE option: -b
    The argument of -b is qing er
    
    optind: 4
    HAVE option: -c
    The argument of -c is 1234
    
     
    
    对于这个过程会调用三次getopt()函数,和第一个输入一样,是找到选项-b和他的参数"qing er",这时optind的值为3,也就意味着,下一次的getopt()要从argv[3]开始搜索,所以第二次调用getopt()函数,找到选项-c和他的参数1234(选项和参数是连在一起的),由于-c1234写在一起,所以他两占一起占用argv[3],所以下次搜索从argv[4]开始,而argv[4]为空,这样第三次调用getopt()函数就会返回-1,循环随之结束。
    接下来我们看一个错误的命令行输入: ./main -z 123
    
    输出为:
    
    optind:1,opterr:1
    --------------------------
    ./main: invalid option -- 'z'
    optind: 2
    Unknown option: z
    
    其中./main: invalid option -- 'z'就是输出到stderr的错误输出。如果把opterr设置为0那么就不会有这条输出。
    
     
    
    在看一个错误的命令行输入: ./main -zheng
    
     
    
    optind:1,opterr:1
    --------------------------
    ./main: invalid option -- 'z'
    optind: 1
    Unknown option: z
    ./main: invalid option -- 'h'
    optind: 1
    Unknown option: h
    optind: 2
    HAVE option: -e
    The argument of -e is ng
    
    前面提到过不带参数的选项可以写在一起,所以当getopt()找到-z的时候,发现在optstring 中没有,这时候他就认为h也是一个选项,也就是-h和-z写在一起了,依次类推,直到找到-e,发现optstring中有。

    最后要说明一下,getopt()会改变argv[]中参数的顺序。经过多次getopt()后,argv[]中的选项和选项的参数会被放置在数组前面,而optind 会指向第一个非选项和参数的位置。看例子

     
    #include <unistd.h>
    #include <stdio.h>
    int main(int argc, char * argv[])
    {
        
        int i;
        printf("--------------------------
    ");
        for(i=0;i<argc;i++)
        {
            printf("%s
    ",argv[i]);
        }
        printf("--------------------------
    ");
           //int aflag=0, bflag=0, cflag=0;
        
           int ch;
        printf("
    
    ");
        printf("optind:%d,opterr:%d
    ",optind,opterr);
        printf("--------------------------
    ");
           while ((ch = getopt(argc, argv, "ab:c:de::")) != -1)
           {
            printf("optind: %d
    ", optind);
               switch (ch) 
            {
                   case 'a':
                           printf("HAVE option: -a
    
    ");   
                           break;
                   case 'b':
                           printf("HAVE option: -b
    "); 
                           printf("The argument of -b is %s
    
    ", optarg);
                           break;
                   case 'c':
                           printf("HAVE option: -c
    ");
                           printf("The argument of -c is %s
    
    ", optarg);
                           break;
                   case 'd':
                       printf("HAVE option: -d
    ");
                         break;
                  case 'e':
                        printf("HAVE option: -e
    ");
                        printf("The argument of -e is %s
    
    ", optarg);
                      break;
                  case '?':
                           printf("Unknown option: %c
    ",(char)optopt);
                           break;
                   }
           }
        
           printf("----------------------------
    ");
          printf("optind=%d,argv[%d]=%s
    ",optind,optind,argv[optind]);
    
        printf("--------------------------
    ");
        for(i=0;i<argc;i++)
        {
            printf("%s
    ",argv[i]);
        }
        printf("--------------------------
    ");
        
    
    }
     
    命令行:./main zheng -b "qing er" han -c123 qing
    
     
    
    输出结果为:
    
    --------------------------
    ./main
    zheng
    -b
    qing er
    han
    -c123
    qing
    --------------------------
    
    
    optind:1,opterr:1
    --------------------------
    optind: 4
    HAVE option: -b
    The argument of -b is qing er
    
    optind: 6
    HAVE option: -c
    The argument of -c is 123
    
    ----------------------------
    optind=4,argv[4]=zheng
    --------------------------
    ./main
    -b
    qing er
    -c123
    zheng
    han
    qing
    --------------------------
    
     

    可以看到最开始argv[]内容为:

    ./main
    zheng
    -b
    qing er
    han
    -c123
    qing

    在执行了多次getopt后变成了

    ./main
    -b
    qing er
    -c123
    zheng
    han
    qing

    我们看到,被getopt挑出的选项和对应的参数都按顺序放在了数组的前面,而那些既不是选项又不是参数的会按顺序放在后面。而此时optind为4,即指向第一个非选项也非选项的参数,zheng

    花了40多分钟整理,希望能够给需要的人带来帮助。

    很多时候我都在寻思,为啥要花时间整理,明明已经非常忙碌了,有这点时间休息一下多好,多惬意?

    我总结的原因有一下几个:

    1、总结时会注意到之前没有关注的问题,可以加深对问题的理解。

    2、方便以后忘记的时候查阅

    3、与广大朋友们分享,想想我们从哪些大牛的博客里得到的太多了。我们应当向那些大神学习。把自己学到的分享出来,帮助其他人(虽然我很渣,但是三人行必有我师,应该还是会帮到些人吧)。

    共勉!努力!

    最后给大家介绍一个写的更加全面的文章:http://blog.csdn.net/huangxiaohu_coder/article/details/7475156

  • 相关阅读:
    poj 2728 Desert King
    uva 439 Knight Moves
    hdu 1875 畅通工程再续
    scau实验题 8600 骑士周游问题(有障碍物)
    scau实验题 8596 Longest Ordered Subsequence
    poj 1679 The Unique MST
    uva 527 Oil Deposits
    poj 2533 Longest Ordered Subsequence
    .net 程序员 java 开发入门
    Collation conflict occur at operation on User define funtion & table's column
  • 原文地址:https://www.cnblogs.com/LiuYanYGZ/p/14200228.html
Copyright © 2011-2022 走看看