Программирование для Linux. Профессиональный подход - страница 12
>
> на аргументы. */
>int main(int argc, char* argv[]) (
> int next_option;
> /* Строка с описанием возможных коротких опций. */
> const char* const short_options = "ho:v";
> /* Массив с описанием возможных длинных опций. */
> const struct option long_options[] = {
> { "help", 0, NULL, 'h' },
> { "output", 1, NULL, 'o' },
> { "verbose", 0, NULL, 'v' },
> { NULL, 0, NULL, 0 } /* Требуется в конце массива. */
> };
> /* Имя файла, в который записываются результаты работы
> программы, или NULL, если вывод направляется в поток
> stdout. */
> const char* output_filename = NULL;
> /* Следует ли выводить развернутые сообщения. */
> int verbose = 0;
> /* Запоминаем имя программы, которое будет включаться
> в сообщения. Оно хранится в элементе argv[0] */
> program_name = argv[0];
> do {
> next_option =
> getopt_long(argc, argv, short_options,
> long_options, NULL);
> switch(next_opt ion) {
> case "h": /* -h или --help */
> /* Пользователь запросил информацию об использовании
> программы, нужно вывести ее в поток stdout и завершить
> работу с выдачей кода 0 (нормальное завершение). */
> print_usage(stdout, 0);
> case 'o': /* -о или --output */
> /* Эта опция принимает аргумент -- имя выходного файла. */
> output_filename = optarg;
> break;
> case 'v': /* -v или --verbose */
> verbose = 1;
> break;
> case '?': /* Пользователь ввел неверную опцию. */
> /* Записываем информацию об использовании программы в поток
> stderr и завершаем работу с выдачей кода 1
> (аварийное завершение). */
> print_usage(stderr, 1);
> case -1: /* Опций больше нет. */
> break;
> default: /* Какой-то непредвиденный результат. */
> abort();
> }
> }
> while (next_option != -1);
> /* Обработка опций завершена, переменная OPTIND указывает на
> первый аргумент, не являющийся опцией. В демонстрационных
> целях отображаем эти аргументы, если задан режим VERBOSE. */
> if (verbose) {
> int i;
> for (i = optind; i < argc; ++i)
> printf("Argument: %s\n", argv[i]);
> }
> /* Далее идет основное тело программы... */
> return 0;
>}
Может показаться, что использование функции >getopt_long()
приводит к написанию громоздкого кода, но, поверьте, самостоятельный синтаксический анализ опций командной строки — гораздо более трудоемкая задача. Функция >getopt_long()
достаточно универсальна и гибка в работе с опциями, но лучше не заниматься сложными вещами. Старайтесь придерживаться традиционной структуры задания опций.
2.1.4. Стандартный ввод-вывод
В стандартной библиотеке языка С определены готовые потоки ввода и вывода (>stdin
и >stdout
соответственно). Они используются функциями >scanf()
, >printf()
и целым рядом других библиотечных функций. Согласно идеологии UNIX, стандартные потоки можно перенаправлять. Это позволяет образовывать цепочки программ, связанных посредством каналов (конкретный синтаксис перенаправления потоков и работы с каналами можно узнать в документации к интерпретатору команд).
Есть также стандартный поток ошибок: >stderr
. Программы должны направлять предупреждающие сообщения и сообщения об ошибках в него, а не в поток >stdout
. Это позволяет отделять обычные выводные данные от разного рода служебных сообщений. К примеру, стандартный поток вывода можно направить в файл, а сообщения об ошибках, по-прежнему отображать на консоли. Запись в поток >stderr
осуществляется с помощью функции >fprintf()
:
>fprintf(stderr, ("Error: ..."));
Все три стандартных потока доступны низкоуровневым функциям ввода-вывода (>read()
, >write()
и т.д.) через дескрипторы файлов. В частности, поток >stdin
имеет дескриптор 0, >stdout
— 1, a >stderr
— 2.
При вызове программы иногда требуется одновременно перенаправить потоки вывода и ошибок в файл или канал. Синтаксис подобной операции зависит от используемого интерпретатора команд. В интерпретаторах семейства Bourne shell (включая >bash
, который по умолчанию установлен в большинстве дистрибутивов Linux) это делается так:
>% program > output_file.txt 2>&1
>% program 2>&1 | filter
Запись >2>&1
означает, что файл с дескриптором 2 (>stderr
) объединяется с файле имеющим дескриптор 1 (>stdout
). Обратите внимание на то, что эта запись должна идти после операции перенаправления в файл (первый пример), но перед операцией перенаправления в канал (второй пример).