Программирование для 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). Обратите внимание на то, что эта запись должна идти после операции перенаправления в файл (первый пример), но перед операцией перенаправления в канал (второй пример).