C getopt множественное значение

Мой аргумент таков

./a.out -i file1 file2 file3

Как я могу использовать getopt() для получения 3 (или более) входных файлов? Я делаю что-то вроде этого:

while ((opt = getopt(argc, argv, "i:xyz.."))!= -1){
  case 'i':
     input = optarg; 
     break;
  ...
}

Я получаю только file1; как получить file2, file3?


person w00d    schedule 15.10.2010    source источник
comment
Обратите внимание, что вопрос предоставление двух аргументов в параметр командной строки с использованием getopt() предоставляет некоторые возможности, не упомянутые здесь.   -  person Jonathan Leffler    schedule 05.06.2014
comment
Ответы ниже этой настройки optind в коде программы ходят по тонкому льду. Нет задокументированных требований, чтобы getopt() вел себя, если вы изменяете optind или optarg в вызывающем коде. Конечно, большинство современных и правдоподобных реализаций не будут иметь проблем, но гипотетическая реализация может записывать свое внутреннее состояние в неглобальные переменные и просто устанавливать глобальные переменные по мере возврата. Такая реализация соответствовала бы спецификации POSIX для getopt(), но показано не будет работать.   -  person Jonathan Leffler    schedule 05.06.2014


Ответы (5)


Если необходимо, вы можете начать с argv[optind] и самостоятельно увеличить optind. Однако я бы рекомендовал против этого, так как считаю такой синтаксис плохой формой. (Как узнать, что вы достигли конца списка? Что, если у кого-то есть файл с - в качестве первого символа?)

Я думаю, что было бы лучше изменить ваш синтаксис на:

/a.out -i file1 -i file2 -i file3

Или рассматривать список файлов как позиционные параметры:

/a.out file1 file2 file3
person jamesdlin    schedule 15.10.2010
comment
Спасибо, jamesdlin, я посмотрю на [optind], так как у меня довольно много аргументов, кроме -i - person w00d; 15.10.2010

Я знаю, что это довольно старо, но я наткнулся на это в поисках решения.

while((command = getopt(argc, argv, "a:")) != -1){

    switch(command){
        case 'a':

        (...)

        optind--;
        for( ;optind < argc && *argv[optind] != '-'; optind++){
              DoSomething( argv[optind] );         
        }

        break;
    }

Я обнаружил, что int optind (extern, используемый getopt() ) указывает на следующую позицию после «текущего argv», выбранного getopt (); Вот почему я уменьшаю его в начале.

Прежде всего цикл for проверяет, находится ли значение текущего аргумента в пределах границ argv (argc — это длина массива, поэтому последняя позиция в массиве argv равен argc-1). Вторая часть && сравнивает, равен ли первый символ следующего аргумента '-'. Если первый символ равен '-', то у нас заканчиваются следующие значения для текущего аргумента, иначе argv[optind] является нашим следующим значением. И так до тех пор, пока argv не закончится или в аргументе не закончатся значения.

В конце увеличьте optind для проверки следующего аргумента.

Обратите внимание, что поскольку мы проверяем 'optind ‹ argc', первая вторая часть условия не будет выполнена, пока первая часть не станет истинной, поэтому не беспокойтесь о чтении за пределами массива.

PS Я совсем новый программист на C, если у кого-то есть улучшения или критические замечания, поделитесь ими.

person GoTTimw    schedule 02.11.2011
comment
Это довольно старо, но я подумал, что могу добавить одну критику. Вы должны не только проверить «-», но и убедиться, что strlen(argv[optind]) равно 2. Это гарантирует, что он будет правильно обрабатывать параметры, начинающиеся с дефиса. Этот код был полезен для меня, хотя! +1 - person TheBat; 19.05.2015

Обратите внимание, что несовместимое с glibc расширение перестановки аргументов остановит любую попытку использовать несколько аргументов для -i таким образом. А в системах, отличных от GNU, «второй аргумент для -i» будет интерпретироваться как первый аргумент, не являющийся параметром, что остановит любой дальнейший анализ параметров. Имея в виду эти проблемы, я бы отказался от getopt и написал свой собственный синтаксический анализатор командной строки, если вы хотите использовать этот синтаксис, поскольку этот синтаксис не поддерживается getopt.

person R.. GitHub STOP HELPING ICE    schedule 15.10.2010

Я посмотрел и попробовал приведенный выше код, но нашел свое решение немного проще и работал лучше для меня:

Обработка, которую я хотел, была:

-m mux_i2c_group mux_i2c_out

(требуется 2 аргумента).

Вот как это получилось у меня:

case 'm':
    mux_i2c_group = strtol(optarg, &ch_p, 0);

    if (optind < argc && *argv[optind] != '-'){
        mux_i2c_out = strtol(argv[optind], NULL, 0);
        optind++;
    } else {
        fprintf(stderr, "\n-m option require TWO arguments <mux_group> "
                        "<mux_out>\n\n");
        usage();
    }

    use_mux_flag = 1;
    break;

Это захватило первое значение из меня, как обычно, а затем просто искало второе, НЕОБХОДИМОЕ значение.

person Andrew Ward    schedule 11.08.2012
comment
хорошее решение! Спасибо!:) - person alexanderzhirov; 15.02.2021

Решение GoTTimw оказалось для меня очень полезным. Однако я хотел бы упомянуть еще об одной идее, которая здесь еще не была предложена.

Передавайте аргументы как одну строку таким образом.

./a.out -i "file1 file2 file3"

Затем вы получаете одну строку в качестве одного аргумента, и вам нужно только разделить ее по пробелу.

person Dmytro Oliinychenko    schedule 26.12.2019