如何使用getopt_long解析多个参数

How do I use getopt_long to parse multiple arguments?

本文关键字:参数 long 何使用 getopt      更新时间:2023-10-16
#include <iostream>
#include <getopt.h>
#define no_argument 0
#define required_argument 1 
#define optional_argument 2

int main(int argc, char * argv[])
{
  std::cout << "Hello" << std::endl;
  const struct option longopts[] =
  {
    {"version",   no_argument,        0, 'v'},
    {"help",      no_argument,        0, 'h'},
    {"stuff",     required_argument,  0, 's'},
    {0,0,0,0},
  };
  int index;
  int iarg=0;
  //turn off getopt error message
  opterr=1; 
  while(iarg != -1)
  {
    iarg = getopt_long(argc, argv, "s:vh", longopts, &index);
    switch (iarg)
    {
      case 'h':
        std::cout << "You hit help" << std::endl;
        break;
      case 'v':
        std::cout << "You hit version" << std::endl;
        break;
      case 's':
        std::cout << "You hit stuff" << std::endl;
        if(optarg)
          std::cout << "Your argument(s): " << optarg << std::endl;
        break;
    }
  }
  std::cout << "GoodBye!" << std::endl;
  return 0; 
}

期望输出:

./a.out --stuff someArg1 someArg2
Hello
You hit stuff
Your agument(s): someArg1 someArg2
GoodBye!

getopt 在处理完所有选项参数后返回 -1。--stuff被识别为接受参数的选项,在本例中为 someArg1 .someArg2 arg 不以 --- 开头,因此是一个选项。默认情况下,这将排列到 argv 的末尾。getopt 返回 -1 后,所有非选项参数将从 optind argvargc-1

while (iarg != -1) {
    iarg = getopt_long(argc, argv, "s:vh", longopts, &index);
    // ...
}
for (int i = optind; i < argc; i++) {
    cout << "non-option arg: " << argv[i] << std::endl;
}

如果将单个-添加到 optstring 的开头,getopt将返回 1(而不是"1"(并将 optarg 指向非选项参数:

while (iarg != -1) {
    iarg = getopt_long(argc, argv, "-s:vh", longopts, &index);
    switch (iarg)
    {
      // ...
      case 1:
        std::cout << "You hit a non-option arg:" << optarg << std::endl;
        break;
    }
}

./a.out --stuff someArg1 someArg2行中,shell 将三个参数解释为 a.out。您希望 shell 将"someArg1 someArg2"解释为一个参数 - 因此请将单词放在引号中:

./a.out --stuff "someArg1 someArg2"

我正在研究Windows,所以我不得不从这个优秀的来源编译getopt和getopt_long

我修改了 getopt_long.c(下图(以适应两个输入参数。我没有为多个参数的更一般的情况而烦恼,因为这需要比我的时间/需要更多(和更干净(的返工。第二个参数放在另一个全局参数 "optarg2" 中。

如果你不需要从源代码编译getopt,弗兰克上面的回答就更优雅了。

extern char * optarg2
.
.
.
int getopt_long(nargc, nargv, options, long_options, index) 
{
.
.
.
if (long_options[match].has_arg == required_argument ||
            long_options[match].has_arg == optional_argument ||
            long_options[match].has_arg == two_req_arguments) {
            if (has_equal)
                optarg = has_equal;
            else
                optarg = nargv[optind++];
            if (long_options[match].has_arg == two_req_arguments) {
                optarg2 = nargv[optind++];
            }
        }
        if ((long_options[match].has_arg == required_argument ||
             long_options[match].has_arg == two_req_arguments)
            && (optarg == NULL)) {
            /*
             * Missing argument, leading :
             * indicates no error should be generated
             */
            if ((opterr) && (*options != ':'))
                (void)fprintf(stderr,
                  "%s: option requires an argument -- %sn",
                  __progname(nargv[0]), current_argv);
            return (BADARG);
        }
        if ((long_options[match].has_arg == two_req_arguments)
            && (optarg2 == NULL)) {
            /*
             * Missing 2nd argument, leading :
             * indicates no error should be generated
             */
            if ((opterr) && (*options != ':'))
                (void)fprintf(stderr,
                  "%s: option requires 2nd argument -- %sn",
                  __progname(nargv[0]), current_argv);
            return (BADARG);
        }

您还需要在getopt.h中添加一个定义,以根据需要为"two_required_args"或"multiple_args"添加定义。

编辑:我不擅长降价

optarg 指向 "someArg1",argv[optind] 如果存在并且不是一个选项,则为 "someArg2"。您可以简单地使用它,然后通过增加 optind 来使用它。

case 's':
    std::cout << "You hit stuff" << std::endl;
    if (optind < argc && argv[optind][0] != '-') {
       std::cout << "Your argument(s): " << optarg << argv[optind] << std::endl;
       optind++;
    } else {
        printusage();
    }
    break;

请注意,这可以适用于任意数量的参数:

case 's':
    std::cout << "You hit stuff." << std::endl;
    std::cout << "Your arguments:" std::endl << optarg << std::endl;
    while (optind < argc && argv[optind][0] != '-') {
       std::cout << argv[optind] << std::endl;
       optind++;
    } 
    break;

C++ getopt-long command-line-arguments