У меня есть программа, которая берет различные параметры командной строки. Ради упрощения мы скажем, что требуется 3 флага, -a
, -b
, и -c
, и используйте следующий код для парсинга моих аргументов:
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;
}
}
примечание: a, и b берут параметры после флага.
Но я сталкиваюсь с проблемой, если я вызываю свою программу, говорят с
./myprog -a -b parameterForB
где я забыл parameterForA, parameterForA (представленный optarg) возвращается как -b
и parameterForB рассмотрен, возможность без параметра и optind установлена на индекс parameterForB в argv.
Желаемое поведение в этой ситуации было бы этим ':'
возвращается после того, как никакой аргумент не найден для -a
, и Missing option.
печатается к стандартной погрешности. Однако то единственное происходит если -a
последний параметр, переданный в программу.
Я предполагаю, что вопрос: есть ли способ сделать getopt()
предположите, что никакие опции не начнутся -
?
См. определение стандарта POSIX для getopt
. Там говорится, что
Если [getopt] обнаруживает отсутствующий опцию-аргумент, он должен вернуть символ двоеточия ( ':' ), если первый если первый символ строки optstring был двоеточием, или символ вопросительного знака ( '?' ) в противном случае.
Что касается этого определения,
- Если опция была последним символом в строке, на которую указывает элемент argv, то optarg должен содержать следующий элемент argv, а optind увеличивается на 2. Если полученное значение optind больше, чем argc, это указывает на отсутствует опция-аргумент, и getopt() возвращает признак ошибки.
- В противном случае optarg должен указывать на строку, следующую за символом опции в этом элементе argv, и optind должен быть увеличен на 1.
Похоже, что getopt
определен не для того, чтобы делать то, что вы хотите, поэтому вам придется реализовать проверку самостоятельно. К счастью, вы можете сделать это, проверив *optarg
и изменив optind
самостоятельно.
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 ( …
Полное раскрытие информации: я не эксперт в этом вопросе.
Будет ли этот пример с gnu.org полезным? Кажется, справляется с "?" в случаях, когда не был указан ожидаемый аргумент:
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 ();
}
update: Возможно, следующее сработает как исправление?
while((c = getopt(argc, argv, ":a:b:c")) != EOF)
{
if (optarg[0] == '-')
{
c = ':';
}
switch (c)
{
...
}
}
Если вы работаете на C ++, я рекомендую boost :: program_option для анализа аргумента командной строки:
Существует довольно много различных версий getopt
, так что даже если вы сможете заставить его работать для одной версии, вероятно, найдется по крайней мере пять других, для которых ваш обходной путь будет ломаться. Если у вас нет веских причин использовать getopt, я бы рассмотрел что-нибудь другое, например Boost.Program_options.