Как заставить getopt пройти по всему argv
У меня есть цикл, в котором с помощью getopt считываются флаги для grep и, когда вылавливает нужный, говорит структуре, что флаг был введен
int rez = 0;
opterr = 0;
char ** for_patterns = malloc(sizeof(char *));
while ((rez = getopt(argc, argv, "eivnlc")) != -1) {
switch (rez) {
case 'e':
info->flag_e = true;
find_patterns(argc, argv, for_patterns);
break; case 'i':
info->flag_i = true;
break; case 'l':
info->flag_l = true;
break; case 'v':
info->flag_v = true;
break; case 'c':
info->flag_c = true;
break; case 'n':
info->flag_n = true;
break;
default:
printf("жесть"); return false;
}
}
Но возможны же и ситуации по типу grep -e include int 1.txt -i. В таких случаях гетоп сдается и не видит -i. Как это можно исправить?
Ответы (1 шт):
При использовании getopt "по умолчанию" ключ -i в конце списка аргументов должен попадать в цикл разбора.
Такое впечатление, что у вас либо определена environment переменная POSIXLY_CORRECT, либо какая-то нестандартная реализация getopt
(кстати, в какой ОС вы пишете? а не меняет ли функция find_patterns() содержимое argv?)
Как описано в man getopt, эта функция по умолчанию переставляет элементы argv[] таким образом, что в итоге nonoption аргументы оказываются в конце и переменная optind после цикла разбора содержит индекс первого из них.
Возможно, что в вашем коде за ключем -e должен следовать его аргумент. Если это так, то в строке ключей, передаваемой в getopt, после e нужно поставить символ :. Тогда при обнаружении -e в цикле разбора аргументов переменная optarg будет указывать на этот аргумент.
Для демонстрации сказанного, на основе вашего кода я набросал пример (предполагающий наличие аргумента у ключа -e), который просто распечатывает найденные ключи и "свободные" аргументы (после разбора ключей).
int
main (int ac, char *av[])
{
int rez = 0;
opterr = 0;
//char ** for_patterns = malloc(sizeof(char *));
while ((rez = getopt(ac, av, "e:ivnlc")) != -1) {
switch (rez) {
case 'e':
puts("info->flag_e = true;");
printf("-e arg = '%s'\n", optarg);
// find_patterns(argc, argv, for_patterns);
break;
case 'i':
puts("info->flag_i = true; ");
break;
case 'l':
puts("info->flag_l = true; ");
break;
case 'v':
puts("info->flag_v = true;");
break;
case 'c':
puts("info->flag_c = true;");
break;
case 'n':
puts("info->flag_n = true;");
break;
default:
printf("жесть");
//return false;
return -1;
}
}
printf("flags processed, optind = %d\n", optind);
if (optind < ac) {
puts("free args:");
for (int i = optind; i < ac; i++)
puts(av[i]);
}
return puts("End") == EOF;
}
и сделал пару запусков с интересующими вас аргументами.
avp@avp-desktop:~/avp/hashcode$ gcc ttt.c
avp@avp-desktop:~/avp/hashcode$ POSIXLY_CORRECT=1 ./a.out -e include int 1.txt -i
info->flag_e = true;
-e arg = 'include'
flags processed, optind = 3
free args:
int
1.txt
-i
End
avp@avp-desktop:~/avp/hashcode$ ./a.out -e include int 1.txt -i
info->flag_e = true;
-e arg = 'include'
info->flag_i = true;
flags processed, optind = 4
free args:
int
1.txt
End
На всякий случай, если ключ (option) повторяется, то повторно он также доступен:
avp@avp-desktop:~/avp/hashcode$ ./a.out -e include int 1.txt -i -e '*.c'
info->flag_e = true;
-e arg = 'include'
info->flag_i = true;
info->flag_e = true;
-e arg = '*.c'
flags processed, optind = 6
free args:
int
1.txt
End
avp@avp-desktop:~/avp/hashcode$
P.S.
Хорошее описание getopt находится в GNU C Library Reference Manual
Также там есть глава Program Arguments с подробным описанием правил использования аргументов командной строки и нескольких средств для их разбора.