Comment puis-je utiliser getopt_long pour analyser plusieurs arguments?
-
26-10-2019 - |
Question
#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;
}
sortie désiré:
./a.out --stuff someArg1 someArg2
Hello
You hit stuff
Your agument(s): someArg1 someArg2
GoodBye!
La solution
getopt renvoie -1 lorsque toutes les options args ont été traitées. Le --stuff
est reconnu comme une option qui prend un argument, dans ce cas someArg1
. Le arg someArg2
ne démarre pas avec -
ou --
, il est si pas une option. Par défaut, ce sera permuté à la fin de argv
. Après getopt renvoie -1, tous les args non-option sera en argv
de optind
à 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 vous ajoutez un seul -
au début de optstring
, getopt
retournera 1 ( '1') et le point optarg
au paramètre non-options:
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;
}
}
Autres conseils
Dans la ligne ./a.out --stuff someArg1 someArg2
les interprète shell trois arguments à a.out. Vous voulez que le shell d'interpréter « someArg1 someArg2 » comme un argument - donc mettre les mots entre guillemets:
./a.out --stuff "someArg1 someArg2"
Je travaille sur les fenêtres, donc je devais compiler getopt et getopt_long cette excellente source de
I modifié getopt_long.c (ci-dessous) pour recevoir deux arguments d'entrée. Je ne l'ai pas pris la peine avec le cas plus général de multiples arguments étant donné qu'il faudrait plus (et plus propre) réusinage que je n'avais le temps / besoin. Le second argument est placé dans un autre monde, "optarg2".
Si vous n'avez pas besoin de compiler getopt de la source, la réponse de Frank ci-dessus est plus élégant.
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);
}
Vous aurez également besoin d'ajouter DEFINE dans getopt.h pour « two_required_args » ou « multiple_args » comme bon vous semble.
edit: je suis mauvais à démarquage
points de OPTARG à "someArg1" et argv [optind] est "someArg2" si elle existe et est pas une option. Vous pouvez simplement l'utiliser et consommer par incrémenter 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;
Notez cela peut fonctionner pour un nombre arbitraire d'arguments:
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;