代码之家  ›  专栏  ›  技术社区  ›  hayalci

getopt不分析参数的可选参数

  •  40
  • hayalci  · 技术社区  · 15 年前

    在C语言中,getopt_long不将可选参数解析为命令行参数参数参数。

    当我运行程序时,不能像下面运行的示例那样识别可选参数。

    $ ./respond --praise John
    Kudos to John
    $ ./respond --blame John
    You suck !
    $ ./respond --blame
    You suck !
    

    这是测试代码。

    #include <stdio.h>
    #include <getopt.h>
    
    int main(int argc, char ** argv )
    {
        int getopt_ret, option_index;
        static struct option long_options[] = {
                   {"praise",  required_argument, 0, 'p'},
                   {"blame",  optional_argument, 0, 'b'},
                   {0, 0, 0, 0}       };
        while (1) {
            getopt_ret = getopt_long( argc, argv, "p:b::",
                                      long_options,  &option_index);
            if (getopt_ret == -1) break;
    
            switch(getopt_ret)
            {
                case 0: break;
                case 'p':
                    printf("Kudos to %s\n", optarg); break;
                case 'b':
                    printf("You suck ");
                    if (optarg)
                        printf (", %s!\n", optarg);
                    else
                        printf ("!\n", optarg);
                    break;
                case '?':
                    printf("Unknown option\n"); break;
            }
        } 
        return 0;
    }
    
    4 回复  |  直到 7 年前
        1
  •  81
  •   Jonathan Leffler    9 年前

    虽然glibc文档或getopt手册页中没有提到,但是长样式命令行参数的可选参数需要“等号”(=)。将可选参数与参数分隔开的空间不起作用。

    使用测试代码运行的示例:

    $ ./respond --praise John
    Kudos to John
    $ ./respond --praise=John
    Kudos to John
    $ ./respond --blame John
    You suck !
    $ ./respond --blame=John
    You suck , John!
    
        2
  •  13
  •   Brian Vandenberg    9 年前

    手册页当然不能很好地记录它,但是源代码有一点帮助。

    简单地说:你应该做如下的事情(尽管这可能有点过于迂腐):

    if(   !optarg
       && optind < argc // make sure optind is valid
       && NULL != argv[optind] // make sure it's not a null string
       && '\0' != argv[optind][0] // ... or an empty string
       && '-' != argv[optind][0] // ... or another option
      ) {
      // update optind so the next getopt_long invocation skips argv[optind]
      my_optarg = argv[optind++];
    }
    /* ... */
    

    从“内部”前面的注释中:

    如果 getopt 找到另一个选项字符,它返回该字符, 更新 optind nextchar 所以下次打电话给 盖特 可以 使用以下选项字符或argv元素继续扫描。

    如果没有更多的选项字符, 盖特 返回- 1。 然后 奥廷德 是第一个argv元素的argv索引 这不是一个选择。(argv元素已排列 所以那些不是选项的现在排在最后。) <-- a note from me: if the 3rd argument to getopt_long starts with a dash, argv will not be permuted

    如果optstring中的char后跟冒号,则表示它需要arg, 所以下面的文本在同一个argv元素中,或者下面的文本 argv元素,返回到 optarg . 两个冒号意味着一个选项 需要可选参数;如果当前argv元素中有文本, 它被送回 奥塔格 , 否则 奥塔格 设置为零 .

    …尽管你必须在两行之间读些东西。以下是您想要的:

    #include <stdio.h>
    #include <getopt.h>
    
    int main(int argc, char* argv[] ) {
      int getopt_ret;
      int option_index;
      static struct option long_options[] = {
          {"praise",  required_argument, 0, 'p'}
        , {"blame",  optional_argument, 0, 'b'}
        , {0, 0, 0, 0}
      };
    
      while( -1 != ( getopt_ret = getopt_long(  argc
                                              , argv
                                              , "p:b::"
                                              , long_options
                                              , &option_index) ) ) {
        const char *tmp_optarg = optarg;
        switch( getopt_ret ) {
          case 0: break;
          case 1:
            // handle non-option arguments here if you put a `-`
            // at the beginning of getopt_long's 3rd argument
            break;
          case 'p':
            printf("Kudos to %s\n", optarg); break;
          case 'b':
            if(   !optarg
               && NULL != argv[optindex]
               && '-' != argv[optindex][0] ) {
              // This is what makes it work; if `optarg` isn't set
              // and argv[optindex] doesn't look like another option,
              // then assume it's our parameter and overtly modify optindex
              // to compensate.
              //
              // I'm not terribly fond of how this is done in the getopt
              // API, but if you look at the man page it documents the
              // existence of `optarg`, `optindex`, etc, and they're
              // not marked const -- implying they expect and intend you
              // to modify them if needed.
              tmp_optarg = argv[optindex++];
            }
            printf( "You suck" );
            if (tmp_optarg) {
              printf (", %s!\n", tmp_optarg);
            } else {
              printf ("!\n");
            }
            break;
          case '?':
            printf("Unknown option\n");
            break;
          default:
            printf( "Unknown: getopt_ret == %d\n", getopt_ret );
            break;
        }
      }
      return 0;
    }
    
        3
  •  1
  •   user5081924    9 年前

    我也遇到了同样的问题,来到这里。然后我意识到了这一点。 你没有多少“可选参数”的用例。如果需要某个选项,请从程序逻辑中进行检查,如果某个选项是可选的,则无需执行任何操作,因为在getopt级别,所有选项都是可选的,它们不是必需的,因此不存在“可选\参数”的用例。希望这有帮助。

    PS:对于上面的例子,我认为正确的选择是 --赞美--赞美的名字“名字”--责备--责备的名字“名字”

        4
  •  -3
  •   jcardenas    7 年前

    如果在没有空格字符的参数旁边编写参数,则两者都不相等。例如:

    $ ./respond --blameJohn
    You suck John!