Почти всем сложным программам для работы требуется входные параметры (опции, аргументы - называйте как хотите), от значения которых строится последовательность работы алгоритма заложенного в программе или используются различные источники данных.
Вы наверняка знаете, что передача параметров в программу на C/C++ осуществляется через массив функции main(). Так повелось, что он называется argv (от arguments values - значения аргументов), но в принципе его можно назвать и по другому. Количество этих параметров передается через переменную argc (от arguments counter - счетчик аргументов).
Программа, для работы которой требуется набор входных параметров задается при помощи специального определения функции main():
int main(int argc, char *argv[]){ }; int main(int argc, char **argv){ };
Давайте напишем маленькую программку, которая выводит значения переданных параметров:
// программа test.c #include <stdio.h> int main(int argc, char *argv[]){ int i = 0; for (i = 0; i < argc; i++){ printf("Argument %d: %s\n", i, argv[i]); }; };
Сохраняем в файл test.c и компилируем:
dron:~# gcc test.c -o test
После этого попробуем запустить программу:
dron:~# ./test Argument 0: ./test
Передадим несколько параметров:
dron:~# ./test qwe sdf fgh hjk kl 123 --help Argument 0: ./test Argument 1: qwe Argument 2: sdf Argument 3: fgh Argument 4: hjk Argument 5: kl Argument 6: 123 Argument 7: --help
В качестве первого параметра программе всегда передается ее имя и таким образом программа может узнать свое название, т.е. имя файла, в котором она содержится.
Но моя цель не говорить о том, как передаются параметры, а как с ними работать. Для начала надо вспомнить, что в системе Linux существует два вида параметров: короткие и длинные. Короткие параметры начинаются с одного дефиса и имеют длину в один символ, их просто и быстро набирать в командной строке. Длинные параметры начинаются с двух дефисов и могут иметь длинное имя, которое целесообразно использовать в скриптах (чтобы потом можно было вспомнить, что и как происходит). Кроме этого любой параметр может иметь значение, а может и не иметь. Приведу для примера несколько параметров:
-h - короткий параметр --help - длинный параметр -s 10 - параметры со значениями --size 10 --size=10
Так вот, существует несколько специальных функций предназначенных для разбора списка переданных параметров:
Давайте разберемся с работой первой функции - getopt(...). Ее определение выглядит следующим образом:
#include <unistd.h> int getopt(int argc, char * const argv[], const char *optstring); extern char *optarg; extern int optind, opterr, optopt;
Эта функция последовательно перебирает переданные параметры в программу. Для работы в функцию передается количество параметров argc, массив параметров argv[] и специальная строка optstring, в которой перечисляются названия коротких параметров и признаки того, что параметры должны иметь значение. Например, если программа должна воспринимать три параметра a, b, F , то такая строка бы выглядела как "abF". Если параметр должен иметь значение, то после буквы параметра ставится двоеточие, например параметр F и d имеют значения, а параметры e, a и b не имеют, тогда эта строка могла бы выглядеть как "eF:ad:b". Если параметр может иметь (т.е. может и не иметь) значение, то тогда ставится два знака двоеточия, например "a::" (это специальное расширение GNU). Если optstring содержит "W:", то тогда параметр -W opt переданный в программу, будет восприниматься как длинный параметр --opt. Это связано с тем, что параметр W зарезервирован в POSIX.2 для расширения возможностей.
Для перебора параметров функцию getopt() надо вызывать в цикле. В качестве результата возвращется буква названия параметра, если же параметры кончились, то функция возвращает -1. Индекс текущего параметра хранится в optind, а значение параметра помещается в optarg (указатель просто указывает на элемент массива argv[]). Если функция находит параметр не перечисленный в списке, то выводится сообщение об ошибке в stderr и код ошибки сохраняется в opterr, при этом в качестве значения возврящается "?". Вывод ошибки можно запретить, если установить opterr в 0.
#include <stdio.h> #include <unistd.h> int main(int argc, char *argv[]) { int rez = 0; // opterr = 0; while ( (rez = getopt(argc, argv, "ab:C::d")) != -1){ switch (rez) { case 'a': printf("found argument \"a\".\n"); break; case 'b': printf("found argument \"b = %s\".\n", optarg); break; case 'C': printf("found argument \"C = %s\".\n", optarg); break; case 'd': printf("found argument \"d\"\n"); break; case '?': printf("Error found !\n"); break; } // switch } // while } // main
Попробуем скомпилировать данную программку и запустить:
dron:~# gcc test.c -o test dron:~# ./test -a -b -d -C found argument "a". found argument "b = -d". found argument "C = (null)". dron:~# ./test -a -b -C -d found argument "a". found argument "b = -C". found argument "d" dron:~# ./test -a -b1 -C -d found argument "a". found argument "b = 1". found argument "C = (null)". found argument "d" dron:~# ./test -b1 -b2 -b 15 found argument "b = 1". found argument "b = 2". found argument "b = 15".
Давайте посмотрим, как функция getopt вылавливает ошибки. Попробуем задать параметр, которого нет в списке:
dron:~# ./test -h -a ./test: invalid option -- h Error found ! found argument "a".
Как я и говорил, функция вывела сообщение об ошибке в stderr. Давайте выключим вывод сообщений, для этого надо где-то в программе перед вызовом функции вставить opterr=0;. Компилируем и запускаем:
dron:~# ./test -h -a Error found ! found argument "a".
Теперь, как видите, сообщение больше не выдается, зато как и раньше можно обработать ошибку самому.