Как использовать getopt_long для анализа нескольких аргументов?
-
26-10-2019 - |
Вопрос
#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, все ARG, не являющиеся OPTION, будут в argv
из 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;
}
Если вы добавите один -
к началу 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
Оболочка интерпретирует три аргумента с A.out. Вы хотите, чтобы оболочка интерпретировала «somearg1 somearg2» как один аргумент - так что поместите слова в кавычки:
./a.out --stuff "someArg1 someArg2"
Я работаю над Windows, поэтому мне пришлось компилировать getopt и getopt_long из Этот превосходный источник
Я изменил getopt_long.c (ниже), чтобы приспособиться к двум входным аргументам. Я не беспокоился о более общем случае нескольких аргументов, так как это потребовало бы большего (и более чистого) переработки, чем у меня было время/необходимость. Второй аргумент находится в другом глобальном, «Optarg2».
Если вам не нужно компилировать Getopt из Source, ответ Фрэнка выше элегантен.
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);
}
Вам также необходимо добавить определение в getopt.h для "two_required_args" или "Multiple_args", как вы видите в форме.
РЕДАКТИРОВАТЬ: Я плохо себя в маркедауне
Optarg указывает на «Somearg1», а Argv [Optind] - «соморг2», если он существует, и не является вариантом. Вы можете просто использовать его, а затем потреблять, увеличив 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;