Книга: Основы программирования в Linux

Обработка перенаправленного вывода

Обработка перенаправленного вывода

Для программ, выполняющихся в ОС Linux, даже интерактивных, характерно перенаправление своего ввода и вывода как в файлы, так и в другие программы. Давайте рассмотрим поведение вашей программы при перенаправлении ее вывода в файл.

$ ./menu1 > file
a
q
$

Такой результат можно было бы считать успешным, потому что вывод перенаправлен в файл вместо терминала. Однако бывают случаи, когда нужно помешать такому исходу событий или отделить приглашения или подсказки, которые пользователь должен видеть, от остального вывода, благополучно перенаправляемого в файл.

О перенаправлении стандартного вывода можно судить по наличию низкоуровневого дескриптора файла, ассоциированного с терминалом. Эту проверку выполняет системный вызов isatty. Вы просто передаете ему корректный дескриптор файла, и он проверяет, связан ли этот дескриптор в данный момент с терминалом.

#include <unistd.h>
int isatty(int fd);

Системный вызов isatty возвращает 1, если открытый дескриптор файла fd связан с терминалом, и 0 в противном случае.

В данной программе используются файловые потоки, но isatty оперирует только дескрипторами файлов. Для выполнения необходимого преобразования вам придется сочетать вызов isatty с подпрограммой fileno, обсуждавшейся в главе 3.

Что вы собираетесь делать, если стандартный вывод stdout перенаправлен? Просто завершить программу — не слишком хорошо, потому что у пользователя нет возможности выяснить, почему программа аварийно завершила выполнение. Вывод сообщения в stdout тоже не поможет, поскольку оно будет перенаправлено с терминала. Единственное решение — записать сообщение в стандартный поток ошибок stderr, который не перенаправляется командой оболочки > file (упражнение 5.2).

Упражнение 5.2. Проверка для выявления перенаправления вывода

Внесите следующие изменения в директивы включения заголовочных файлов и функцию main программы menu1.с из упражнения 5.1. Назовите новый файл menu2.c.

#include <unistd.h>
...
int main() {
 int choice = 0;
 if (!isatty(fileno(stdout))) {
  fprintf(stderr, "You are not a terminal!n");
  exit(1);
 }
 do {
  choice = getchoice("Please select an action", menu);
  printf("You have chosen: %cn", choice);
 } while (choice != 'q');
 exit(0);
}

Теперь посмотрите на следующий пример вывода:

$ ./menu2
Choice: Please select an action
a — add new record
d — delete record
q — quit
q
You have chosen: q $ ./menu2 > file
You are not a terminal! $

Как это работает

В новом фрагменте программного кода функция isatty применяется для проверки связи стандартного вывода с терминалом и прекращения выполнения программы при отсутствии этой связи. Это тот же самый тест, который командная оболочка использует для решения, нужно ли выводить строки приглашения. Возможно и довольно обычно перенаправление и stdout, и stderr с терминала на другое устройство. Вы можете направить поток ошибок в другой файл:

$ ./menu2 >file 2>file.error
$

или объединить оба выводных потока в одном файле:

$ ./menu2 >file 2>&1
$

(Если вы не знакомы с перенаправлением вывода, прочтите еще раз главу 2, в которой мы более подробно рассматриваем синтаксические правила, связанные с ним.) В данном случае вам нужно отправить сообщение непосредственно на терминал пользователя.

Оглавление книги


Генерация: 1.642. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз