Как сделать передачу аргумента в getopt возможной, но не обязательной?

Вот код

bool grep_parse(grep_info *info, char *argv[], int argc, pattern *patterns,
count *count_patt) {
    opterr = 0;
    int res;
    while ((res = getopt(argc, argv, "e:i:v:n:l:c:")) != -1) {
        switch (res) {
            case 'e':
            info->flag_e = true;
            patterns->e_patterns[count_patt->e_count] = optarg;
            puts("info->flag_e = true;");
            printf("-e arg = '%s'\n", optarg);
            count_patt->e_count++;
            break; case 'i':
            info->flag_i = true; 
            patterns->i_patterns[count_patt->i_count] = optarg;
            count_patt->i_count++;
            break; case 'l':
            info->flag_l = true;
            patterns->l_patterns[count_patt->l_count] = optarg;
            count_patt->l_count++; 
            break; case 'v':
            info->flag_v = true;
            patterns->v_patterns[count_patt->v_count] = optarg;
            count_patt->v_count++;
            break; case 'c':
            patterns->c_patterns[count_patt->c_count] = optarg;
            puts("info->flag_c = true;");
            printf("-c arg = '%s'\n", optarg);
            count_patt->c_count++;
            info->flag_c = true;
            break; case 'n':
            patterns->n_patterns[count_patt->n_count] = optarg;
            count_patt->n_count++;
            info->flag_n = true;
            break;
            default:
            return false;
        }
    }
    printf("flags processed, optind = %d\n", optind);
    if (optind < argc) {
        puts("free args:");
    for (int i = optind; i < argc; i++)
        puts(argv[i]);
    }
    grep_distribution(info, argv, argc, optind, patterns, count_patt);
    return true;
}

void grep_distribution(grep_info *info, char *argv[], 
int argc, int optind, pattern *patterns, count *count_patt) {
    char *file_name = malloc(sizeof(char));
    bool flag = false;
    if (argc - optind > 1) {
        flag = true;
    }
    for (int i = optind; i < argc; i++) {
        file_name = argv[i];
        FILE * file = fopen(argv[i], "r");
        if (!file) {
            printf("жесть с файлом\n");
        } else {
        if (info->flag_c) {
            grep_c(file, patterns, count_patt->c_count, file_name, flag);
        }
        if (info->flag_n) {
            grep_n(file, patterns->n_patterns, count_patt->n_count, file_name, flag);
        }
        if (info->flag_e) {
            grep_e(file, patterns->e_patterns, count_patt->e_count, file_name, flag);
        }
        if (info->flag_i) {
            grep_i(file, patterns->i_patterns, count_patt->i_count, file_name, flag);
        }
        if (info->flag_l) {
            grep_l(file, patterns->l_patterns, count_patt->l_count, file_name, flag);
        }
        if (info->flag_v) {
            grep_v(file, patterns->v_patterns, count_patt->v_count, file_name, flag);
        }
        }
    }
    //free(file_name);
}

Проблема состоит в том, что в случае приведенного ниже примера вывода getopt принимает флаг за аргумент. Можно ли сделать так, чтобы он этого не делал? Флаг может содержать аргументы, но если далее следует другой флаг, то предполагается, что его паттерн распространяется и на предыдущий (как я поняла из работы grep)

Пример вывода:

pe@vo-a1 grep % gcc -Wall -Werror -Wextra test.c            
pe@vo-a1 grep % ./a.out -c -e int -e include test_1_grep.txt
info->flag_c = true;
-c arg = '-e'
flags processed, optind = 3
free args:
int
-e
include
test_1_grep.txt
жесть с файлом
жесть с файлом
жесть с файлом
test_1_grep.txt:0

Ответы (1 шт):

Автор решения: avp

Наверное в man getopt использование optional аргументов описано как-то невнятно.

Если вы хотите, чтобы у ключа -c был необязательный (optional) аргумент, то в строке ключей, передаваемых в getopt() после него надо написать два двоеточия -- ::. Т.е. ваша строка должна иметь вид -- "e:i:v:n:l:c::".

В этом случае аргумент для ключа -c при вызове программы надо задавать без пробела между ключем и аргументом.

Если вызвать программу вот так

./a.out -c123 -e arg

то в цикле разбора аргументов

while ((res = getopt(argc, argv, "e:i:v:n:l:c::")) != -1) {
   switch (res) {
      .....

будет вызван

  case 'c':

и optarg будет равен "123"

При вызове

./a.out -c -e arg

также будет вызван case 'c':, а optarg в этом случае будет установлен в NULL.

→ Ссылка