¿Cómo uso getopt_long para analizar múltiples argumentos?
-
26-10-2019 - |
Pregunta
#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;
}
Salida deseada:
./a.out --stuff someArg1 someArg2
Hello
You hit stuff
Your agument(s): someArg1 someArg2
GoodBye!
Solución
getopt Devuelve -1 cuando todos opción Los args han sido procesados. los --stuff
se reconoce como una opción que toma una discusión, en este caso someArg1
. los someArg2
Arg no comienza con -
o --
, así es no una opción. Por defecto, esto se permitirá hasta el final de argv
. Después getopt Devoluciones -1, todos los args de no opción estarán en argv
de 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;
}
Si agrega un solo -
al comienzo de optstring
, getopt
devolverá 1 (no '1') y apuntará optarg
al parámetro de no opción:
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;
}
}
Otros consejos
En la linea ./a.out --stuff someArg1 someArg2
El shell interpreta tres argumentos a A.Out. Desea que el shell interprete "somearg1 somearg2" como un argumento, así que ponga las palabras en citas:
./a.out --stuff "someArg1 someArg2"
Estoy trabajando en Windows, así que tuve que compilar Getopt y Getopt_long desde Esta excelente fuente
Modifiqué getopt_long.c (a continuación) para acomodar dos argumentos de entrada. No me molesté con el caso más general de múltiples argumentos, ya que eso requeriría más (y más limpio) reelaboración de lo que tenía tiempo/necesidad. El segundo argumento se coloca en otro global, "Optarg2".
Si no necesita compilar Getopt de la fuente, la respuesta de Frank anterior es más 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);
}
También deberá agregar una definición en Getopt.h para "two_required_args" o "múltiple_args" como mejor le parece.
Editar: soy malo en Markdown
Optarg señala "Somearg1" y Argv [Optind] es "Somearg2" si existe y no es una opción. Simplemente puede usarlo y luego consumirlo 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;
Tenga en cuenta que esto puede funcionar para un número arbitrario de argumentos:
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;