Скачиваний:
56
Добавлен:
08.01.2014
Размер:
2.6 Mб
Скачать

2.2. Стандартный ввод, стандартный вывод и стандартный вывод диагностики

2.2.1. Основные понятия

Система UNIX автоматически открывает три дескриптора файла для любой выполняющейся программы. Эти дескрипторы называются стандартным вводом (standard input), стандартным выводом (standard output) и стандартным выводом диагностики (standard error). Они всегда имеют значения 0, 1 и 2 соответственно. Недопустимо путать эти дескрипторы с похожими по названию стандартными потоками stdin, stdout и stderr из стандартной библиотеки ввода/ вывода.

По умолчанию вызов fdread для стандартного ввода приведет к чтению данных с клавиатуры. Аналогично запись в стандартный вывод или стандартный вывод диагностики приведет по умолчанию к выводу сообщения на экран терминала. Это первый пример использования примитивов доступа к файлам для ввода/вывода на устройства, отличные от обычных файлов.

Программа, применяющая эти стандартные дескрипторы файлов, тем не менее, не ограничена использованием терминала. Каждый из этих дескрипторов может быть независимо переназначен, если программа вызывается с использованием средств перенаправления, обеспечиваемых стандартным командным интерпретатором UNIX. Например, команда

$ prog_name < infile

приведет к тому, что при чтении из дескриптора со значением 0 программа будет получать данные из файла infile, а не с терминала, обычного источника для стандартного ввода.

Аналогично все данные, записываемые в стандартный вывод, могут быть перенаправлены в выходной файл, например:

$ prog_name > outfile

Возможно, наиболее полезно то, что можно связать стандартный вывод одной программы со стандартным вводом другой при помощи каналов UNIX. Следующая команда оболочки означает, что все данные, записываемые программой prog_1 в ее стандартный вывод, попадут на стандартный ввод программы prog_2 (такие команды называются конвейерами):

$ prog_1 | prog_2

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

2.2.2. Программа io

В качестве очень простого примера использования стандартных дескрипторов файлов приведем программу io, применяющую системные вызовы fdread и fdwrite и дескрипторы файлов со значениями 0 и 1 для копирования стандартного ввода в стандартный вывод. В сущности, это усеченная версия программы UNIX cat. Обратите внимание на отсутствие вызовов fdopen и fdcreat.

(* Программа io копирует стандартный ввод *)

(* в стандартный вывод *)

uses linux;

const

SIZE=512;

var

nread:longint;

buf:array [0..SIZE-1] of byte;

begin

nread := fdread (0, buf, SIZE);

while nread > 0 do

begin

fdwrite (1, buf, nread);

nread := fdread (0, buf, SIZE);

end;

halt(0);

end.

Предположим, что исходный код этой программы находится в файле iо.pas, который компилируется для получения исполняемого файла io:

$ fpc io.pas

Если теперь запустить программу io на выполнение, просто набрав имя файла программы, то она будет ожидать ввода с терминала. Если пользователь напечатает строку и затем нажмет клавишу Return или Enter на клавиатуре, то программа iо просто выведет на дисплей напечатанную строку, то есть запишет строку в стандартный вывод. При этом диалог с системой в действительности будет выглядеть примерно так:

$ io Пользователь печатает io и нажимает Return

Это строка 1 Пользователь печатает строку и нажимает Return

Это строка 1 Программа io выводит строку на дисплей

.

.

.

После вывода строки на экран программа io будет ожидать дальнейшего ввода. Пользователь может продолжать печатать, и программа io будет послушно выводить каждую строку на экран при нажатии на клавишу Return или Enter.

Для завершения программы пользователь может напечатать строку из единственного символа конца файла. Обычно это символ ^D, то есть Ctrl+D, который набирается одновременным нажатием клавиш Ctrl и D. При этом вызов fdread вернет 0, указывая на то, что достигнут конец файла. Весь диалог с системой мог бы выглядеть примерно так:

$ io

Это строка 1

Это строка 1

Это строка 2

Это строка 2

<Ctrl-D> Пользователь печатает Ctrl+D

$

Обратите внимание, что программа io ведет себя не совсем так, как можно было бы ожидать. Вместо того чтобы считать все 512 символов до начала вывода на экран, как, казалось бы, следует делать, она выводит строку на экран при каждом нажатии клавиши Return. Это происходит из-за того, что вызов fdread, который использовался для ввода данных с терминала, обычно возвращает значение после каждого символа перевода строки для облегчения взаимодействия с пользователем. Если быть еще более точным, это будет иметь место только для обычных настроек терминала. Терминалы могут быть настроены в другом режиме, позволяя осуществлять, например, посимвольный ввод. Дополнительные соображения по этому поводу изложены в главе 9.

Поскольку программа io использует стандартные дескрипторы файлов, к ней можно применить стандартные средства оболочки для перенаправления и организации конвейеров. Например, выполнение команды

$ io < /etc/motd > message

приведет к копированию при помощи программы io сообщения с цитатой дня команды /etc/motd в файл message, а выполнение команды

$ io < /etc/motd | wc

направит стандартный вывод программы io в утилиту UNIX для подсчета числа слов wc. Так как стандартный вывод программы io будет фактически идентичен содержимому /etc/motd, это просто еще один (более громоздкий) способ подсчета слов, строк и символов в файле.

Упражнение 2.15. Напишите версию программы io, которая проверяет наличие аргументов командной строки. Если существует хотя бы один из них, то программа должна рассматривать каждый из аргументов как имя файла и копировать содержимое каждого файла в стандартный вывод. Если аргументы командной строки отсутствуют, то ввод должен осуществляться из стандартного ввода. Как должна действовать программа io, если она не может открыть файл?

Упражнение 2.16. Иногда данные в файле могут медленно накапливаться в течение продолжительного промежутка времени. Напишите версию программы io с именем watch, которая будет выполнять чтение из стандартного ввода до тех пор, пока не встретится символ конца файла, выводя данные на стандартный вывод. После достижения конца файла программа watch должна сделать паузу на пять секунд, а затем снова начать чтение стандартного ввода, чтобы проверить, не поступили ли новые данные, не открывая при этом файл заново и не изменяя положение указателя чтения-записи. Для прекращения работы процесса на заданное время вымажете использовать стандартную библиотечную процедуру delay, которая имеет единственный аргумент – целое число, задающее продолжительность ожидания в миллисекундах. Например, вызов

sleep(5000);

заставляет процесс прекратить работу на 5 секунд. Программа watch аналогична программе readslow, существующей в некоторых версиях UNIX. Посмотрите также в руководстве системы описание ключа -f команды tail.

Соседние файлы в папке Полищук, Семериков. Системное программирование в UNIX средствами Free Pascal