Domanda

#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; 
}

output desiderato:

./a.out --stuff someArg1 someArg2

Hello
You hit stuff
Your agument(s): someArg1 someArg2
GoodBye!
È stato utile?

Soluzione

getopt restituisce -1 quando tutto args sono stati elaborati. Il --stuff è riconosciuto come un'opzione che prende un argomento, in questo caso someArg1. L'arg someArg2 non inizia con - o --, quindi è non un'opzione. Per impostazione predefinita, questo sarà permutata alla fine del argv. Dopo getopt restituisce -1, tutti i args non di opzione saranno in argv da optind a argc-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;
}

Se si aggiunge un singolo - dell'inizio optstring, getopt tornerà 1 (non '1') e il punto optarg al parametro che non sia un'opzione:

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;
    }
}

Altri suggerimenti

Nella riga ./a.out --stuff someArg1 someArg2 le interpreta shell tre argomenti a.out. Si desidera che il guscio di interpretare "someArg1 someArg2" come un argomento - in modo da mettere le parole tra virgolette:

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

sto lavorando su Windows, quindi ho dovuto compilare getopt e getopt_long da questa eccellente fonte

I modificato getopt_long.c (sotto) per ospitare due argomenti di input. Non ho disturbato con il caso più generale di più argomenti dal momento che richiederebbe di più (e più pulita) rielaborazione di quanto ho avuto il tempo / necessità di. Il secondo argomento è collocato in un altro, "optarg2" globale.

Se non c'è bisogno di getopt compilazione dai sorgenti, la risposta di Frank sopra è più elegante.

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 -- %s\n",
                  __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 -- %s\n",
                  __progname(nargv[0]), current_argv);
            return (BADARG);
        }

Sono necessari per aggiungere un definire in getopt.h per "two_required_args" o "multiple_args", come si vede in forma.

Edit: sto male a Markdown

punti OPTARG a "someArg1" e argv [OPTIND] è "someArg2" se esiste e non è un'opzione. Si può semplicemente utilizzare e poi consumarlo incrementando 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;

Nota questo lavoro può per un numero arbitrario di argomenti:

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;

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top