Getopt C не может проанализировать параметры в конце (или между) argv - PullRequest
1 голос
/ 09 февраля 2020

Мне нравится getopt для анализа параметров из аргумента argv. К сожалению, я не могу сделать getopt параметры разбора между неопциями или в конце argv. Пример программы:

#include <stdio.h>
#include <unistd.h>

int o_help = 0;

int main(int argc, char *argv[]) {
    int opt, i;
    while ((opt = getopt(argc, argv, "h")) != -1) {
        switch (opt) {
            case 'h':
                o_help = 1;
                break;
            default:
                return -1;
        }
    }

    printf("o_help=%d\n", o_help);
    for (i = 1; i < argc; i++) {
        printf("%s ", argv[i]);
    }
    printf("\n");
    return 0;
}

Запустив программу в альпийском контейнере на MacOS Mojave, я получаю следующие выходные данные:

$ gcc prog.c
$ ./a.out hello -h world
o_help=0
hello -h world
$ ./a.out -h hello world
o_help=1
-h hello world

Официальная getopt Состояния man-страницы:

По умолчанию getopt () переставляет содержимое argv при сканировании, так что в конечном итоге все неопции заканчиваются.

Поскольку я не указал иное, я ожидаю поведение по умолчанию: 1. анализировать опцию -h и 2. переставлять argv, чтобы неопции были в конце массива. К сожалению, вызов программы типа ./a.out hello -h world не выполняет ни разбора -h, ни перестановки массива. Помощь будет принята с благодарностью.

Ответы [ 2 ]

1 голос
/ 09 февраля 2020

Ответ Марко верен, но «самостоятельно установить glib c» не очень хороший совет, если вы не используете дистрибутив на основе glib c; вы бы сами создавали целую параллельную библиотечную экосистему. Есть пара канонических решений вашей проблемы, которые намного проще.

Одобренный GNU метод использования нестандартного поведения GNU, подобного тому, который вам нужен, - это использование gnulib и autoconf, которые могут автоматически заменить getopt на GNU версия по мере необходимости. Однако это серьезное изменение, и оно требует, чтобы ваша программа была под GPL.

Гораздо более простым решением является использование getopt_long с вырожденным списком длинных опций вместо getopt. Поскольку getopt_long не является стандартной функцией, а расширением, изначально определенным в GNU, ее реализация musl может свободно следовать поведению GNU при перестановке argv, чтобы разрешить смешанные опции и неопциональные аргументы, и делает это.

1 голос
/ 09 февраля 2020

Вы смотрите страницу руководства для glib c версии getopt(). Alpine Linux не использует glib c, он использует musl lib c.

Рассматривая различия между ними, из этой страницы из musl lib c wiki, которую вы можете прочитать:

GNU getopt переставляет argv для вывода параметров вперед, перед аргументами без параметров. musl и стандартная поддержка POSIX getopt прекращают обработку на первом неопциональном аргументе без перестановки .

Итак, решение здесь:

  1. Используйте musl, но переделайте argv самостоятельно перед вызовом getopt().
  2. Установите glib c самостоятельно или используйте уже сделанное Docker изображение .
...