c++ - ejemplo - getopt_long example
getopt no puede detectar el argumento faltante para la opción (5)
Como alternativa para los proyectos sin Boost, tengo un contenedor simple de C ++ solo para el encabezado de getopt
(bajo la Licencia BSD 3-Clause): https://github.com/songgao/flags.hh
Tomado de example.cc
en el repositorio:
#include "Flags.hh"
#include <cstdint>
#include <iostream>
int main(int argc, char ** argv) {
uint64_t var1;
uint32_t var2;
int32_t var3;
std::string str;
bool b, help;
Flags flags;
flags.Var(var1, ''a'', "var1", uint64_t(64), "This is var1!");
flags.Var(var2, ''b'', "var2", uint32_t(32), "var2 haahahahaha...");
flags.Var(var3, ''c'', "var3", int32_t(42), "var3 is signed!", "Group 1");
flags.Var(str, ''s'', "str", std::string("Hello!"), "This is a string, and the description is too long to fit in one line and has to be wrapped blah blah blah blah...", "Group 1");
flags.Bool(b, ''d'', "bool", "this is a bool variable", "Group 2");
flags.Bool(help, ''h'', "help", "show this help and exit", "Group 3");
if (!flags.Parse(argc, argv)) {
flags.PrintHelp(argv[0]);
return 1;
} else if (help) {
flags.PrintHelp(argv[0]);
return 0;
}
std::cout << "var1: " << var1 << std::endl;
std::cout << "var2: " << var2 << std::endl;
std::cout << "var3: " << var3 << std::endl;
std::cout << "str: " << str << std::endl;
std::cout << "b: " << (b ? "set" : "unset") << std::endl;
return 0;
}
Tengo un programa que toma varios argumentos de línea de comandos. Para simplificar, diremos que toma 3 marcas, -a
, -b
y -c
, y usaremos el siguiente código para analizar mis argumentos:
int c;
while((c = getopt(argc, argv, ":a:b:c")) != EOF)
{
switch (c)
{
case ''a'':
cout << optarg << endl;
break;
case ''b'':
cout << optarg << endl;
break;
case '':'':
cerr << "Missing option." << endl;
exit(1);
break;
}
}
nota: a, y b toman parámetros después de la bandera.
Pero me encuentro con un problema si invoco mi programa decir con
./myprog -a -b parameterForB
donde olvidé el parámetroForA, el parámetroForA (representado por optarg) se devuelve como -b
y el parámetroForB se considera una opción sin parámetro y optind se establece en el índice de parámetroForB en argv.
El comportamiento deseado en esta situación sería que '':''
se devuelve después de que no se encuentre ningún argumento para -a
, y la Missing option.
Se imprime al error estándar. Sin embargo, eso solo ocurre en el caso de que -a
sea el último parámetro pasado al programa.
Supongo que la pregunta es: ¿hay una manera de hacer que getopt()
asuma que ninguna opción comenzará con -
?
Existen bastantes versiones diferentes de getopt
, por lo que incluso si puede hacer que funcione para una versión, es probable que haya al menos otras cinco por las cuales se interrumpirá su solución. A menos que tenga una razón abrumadora para usar getopt, consideraría otra cosa, como Boost.Program_options .
Revelación completa: no soy un experto en este asunto.
¿Sería útil este ejemplo de gnu.org? Parece manejar el ''?'' carácter en los casos en que no se proporcionó un argumento esperado:
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case ''a'':
aflag = 1;
break;
case ''b'':
bflag = 1;
break;
case ''c'':
cvalue = optarg;
break;
case ''?'':
if (optopt == ''c'')
fprintf (stderr, "Option -%c requires an argument./n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c''./n", optopt);
else
fprintf (stderr,
"Unknown option character `//x%x''./n",
optopt);
return 1;
default:
abort ();
}
actualización: ¿ Quizás lo siguiente podría funcionar como una solución?
while((c = getopt(argc, argv, ":a:b:c")) != EOF)
{
if (optarg[0] == ''-'')
{
c = '':'';
}
switch (c)
{
...
}
}
Si está trabajando en C ++, boost :: program_option es mi recomendación para analizar el argumento de la línea de comandos:
Ver la definición estándar POSIX para getopt
. Dice que
Si [getopt] detecta un argumento-opción faltante, devolverá el carácter de dos puntos ('':'') si el primer carácter de optstring era un signo de dos puntos, o un carácter de signo de interrogación (''?'') De lo contrario.
En cuanto a esa detección,
- Si la opción era el último carácter en la cadena apuntada por un elemento de argv, entonces optarg contendrá el siguiente elemento de argv, y optind se incrementará en 2. Si el valor resultante de optind es mayor que argc, esto indica un Falta el argumento-opción y getopt () devolverá una indicación de error.
- De lo contrario, optarg apuntará a la cadena que sigue al carácter de opción en ese elemento de argv, y optind se incrementará en 1.
Parece que getopt
está definido para no hacer lo que quieres, así que tienes que implementar la comprobación tú mismo. Afortunadamente, puede hacerlo inspeccionando *optarg
y cambiando la optind
usted mismo.
int c, prev_ind;
while(prev_ind = optind, (c = getopt(argc, argv, ":a:b:c")) != EOF)
{
if ( optind == prev_ind + 2 && *optarg == ''-'' ) {
c = '':'';
-- optind;
}
switch ( …