Любая программа - это "автомат", предназначенный для обработки данных: получая на входе одну информацию, она в результате работы выдает
другую. Хотя входящая и/или выходящая информация может быть и нулевой, т. е. попросту отсутствовать. Те данные, которые передаются
программе для обработки - это ее ввод, то, что она выдает в результате работы - вывод. Организация ввода и вывода для каждой программы -
это задача операционной системы.
Каждая программа работает с данными определенного типа: текстовыми, графическими, звуковыми и т. п. Как, наверное, уже стало
понятно, основной интерфейс управления системой в Linux - это терминал, который предназначен для передачи текстовой информации от
пользователя системе и обратно. Поскольку ввести с терминала и вывести на терминал можно только текстовую информацию, то ввод и вывод
программ, связанных с терминалом, тоже должен быть текстовым. Однако необходимость оперировать с текстовыми данными не ограничивает
возможности управления системой, а, наоборот, расширяет их. Человек может прочитать вывод любой программы и разобраться, что происходит
в системе, а разные программы оказываются совместимыми между собой, поскольку используют один и тот же вид представления данных - текстовый.
Команды и сценарии могут получать входные данные двумя способами: из стандартного входного потока (связан с клавиатурой) или из файла.
Аналогичное разделение существует и при выводе данных: результаты работы команды или сценария по умолчанию направляются на экран терминала,
но можно перенаправить их в файл. Если в процессе работы возникают ошибки. сообщения о них гоже отображаются на экране, поток ошибок
также можно перенаправить в файл.
Рассмотрим сначала пару команд, с помощью которых можно организовать ввод/вывод.
Команды вывода на стандартное устройство вывода
Linux предоставляет несколько команд для вывода сообщений в стандартный поток вывода:
- echo - Вывести строку в стандартный поток вывода.
- printf - Вывести форматированный текст в стандартный
поток вывода.
- yes - Выводить повторяющийся текст в стандартный
поток вывода.
- seq - Вывести последовательность чисел в стандартный
поток вывода
- clear Очистить экран или окно.
Например, при использовании команды echo если указать управляющий символ \с, то по завершении вывода не будет осуществлен
переход в новую строку:
$ echo "Как вас зовут?\c"
Как вас зовут?$
Здесь $ – символ приглашения.
В строке также можно вычислять значения переменных интерпретатора shell и даже других команд. Например, следующая команда
сообщает о том, каков начальный каталог текущего пользователя (переменная среды $HOME) и к какому терминалу он подключен
(команда tty заключена в обратные кавычки, чтобы интерпретатор поместил в строку результат ее выполнения).
$ echo "Ваш начальный каталог - $HOME, вы подключены к терминалу - `tty` "
Ваш начальный каталог - /home/knoppix, вы подключены к терминалу - /dev/tty1
Так как двойные кавычки в интерпретаторе shell имеют специальное назначение, то для того чтобы в выводимую строку включить двойные
кавычки нужно отменить их специальное назначение с помощью обратной косой черты (\). Так отменяется назначение любого специального
символа.
Например, чтобы вывести строку “/dev/tty1” необходимо выполнить:
$echo “\”/dev/tty1\””
Команды ввода из стандартного устройства ввода
Команда read читает одну строку из стандартного входного потока и записывает ее содержимое в указанные переменные.
При указании нескольких переменных в первую из них записывается первое слово, во вторую – второе и т.д. в последнюю – остаток строки.
Следующий сценарий вызывает отдельную команду read для чтения каждой переменной.
$ cat test
#!/bin/bash
echo “Имя: \с”
read name
echo “Фамилия: \c”
read surname
echo “Имя=” $name “Фамилия=” $surname
Тогда для выполнения этого сценария необходимо файлу test дать право выполнения: chmod 0755 test и запустить его ./test.
Результат выполнения:
Имя: Иван
Фамилия: Петров
Имя=Иван Фамилия=Петров
СТАНДАРТНЫЕ ПОТОКИ ВВОДА, ВЫВОДА И ОШИБОК
Каждая запущенная из командного интерпретатора программа получает три открытых потока ввода/вывода:
- стандартный ввод (sldin)
- стандартный вывод( sldout)
- стандартный вывод ошибок (stderr)
По умолчанию эти потоки ассоциированы с терминалом. Т.е. любая программа, не использующая потоки, кроме стандартных,
будет ожидать ввода с клавиатуры терминала, весь вывод этой программы, включая сообщения об ошибках, будет происходить на экран терминала.
При этом с каждым процессом (командой, сценарием и т.п.), выполняемым в интерпретаторе shell, связан рад открытых файлов,
из которых процесс
может читать свои данные: и в которые он может записывать их. Каждый из этих файлов идентифицируется числом, называемым дескриптором файла,
но первые три файла являются потоками ввода/вывода по умолчанию:
Файл Дескриптор
Стандартный поток ввода 0
Стандартный поток вывода 1
Стандартный поток ошибок 2
В действительности создается 12 открытых файлов, но файлы с дескрипторами 0, 1 и 2 резервируются для
стандартных потоков ввода, вывода и ошибок. Пользователи могут также работать с файлами, имеющими дескрипторы от 3 до 9 (зарезервированы).
Файл стандартного потока ввода (sldin) имеет дескриптор 0. Из этого файла процессы извлекают свои входные данные.
По умолчанию входной поток ассоциирован с клавиатурой (устройство /dev/tty), но чаше всего он поступает по каналу от
других процессов или из обычного файла.
Файл стандартного потока вывода (stdout) имеет дескриптор 1. В этот файл записываются все выходные данные процесса.
По умолчанию данные выводятся на экран терминала (устройство/dev/tty), но их можно также перенаправить в файл или послать
по каналу другому процессу.
Файл стандартного потока ошибок (siderr) имеет дескриптор 2. В этот файл записываются сообщения об ошибках, возникающих
в ходе выполнения команды. По умолчанию сообщения об ошибках выводятся на экран терминала (устройство /dev/tty), но их также можно перенаправить в файл. Зачем же для регистрации ошибок выделять специальный файл? Дело в том, что это очень удобный способ выделения из результатов работы команды собственно выходных данных, а также хорошая возможность эффективно организовать ведение различного рода журнальных файлов.
Большое число утилит используют только стандартные потоки. Для таких программ оболочка позволяет независимо перенаправлять
потоки ввода/вывода. Например, можно подавить вывод сообщений
об ошибках, установить ввод или вывод из файла.
Т.е. при вызове команд можно указывать, откуда следует принимать входные данные и куда необходимо направлять выходные данные,
а также сообщения об ошибках. По умолчанию, если не указано иное, подразумевается работа с терминалом: данные вводятся с клавиатуры
и выводятся на экран. Но интерпретатор shell располагает механизмом переадресации, позволяющим ассоциировать стандартные потоки
с различными файлами. При этом во время перенаправления стандартного потока ошибок следует указывать дескриптор файла (2).
Для потоков ввода и вывода делать это не обязательно.
Полезный частный случай использования механизма перенаправления потоков - перенаправление в /dev/null, что позволяет избавиться
от ненужных сообщений на экран. С помощью того же механизма можно создавать пустые файлы:
% cat < /dev/null > myfile - создаст в текущей директории пустой файл myfile.
/dev/null — специальный файл, представляющий собой т. н. «пустое устройство». Запись в него происходит успешно, независимо от объёма
«записанной» информации. Чтение из /dev/null эквивалентно считыванию конца файла EOF.
Перенаправление потоков ввода-вывода осуществляется, подобно DOS (Точнее, синтаксис перенаправления потоков ОС DOS восприняла
от UNIX) с помощью символов:
> - перенаправление стандартного потока вывода
>> - перенаправление стандартного потока вывода в режиме дозаписи
< - перенаправление стандартного потока ввода
<< - получение данные из стандартного потока ввода до тех пор, пока не встретится разделитель
Однако, в отличие от DOS при создании программного канала между двумя процессами
ОС UNIX/Linux запускает оба процесса одновременно и осуществляет передачу информации через системный буфер (без промежуточной записи на
жесткий диск). Таким образом, программные каналы в ОС UNIX/Linux являются весьма эффективным способом обмена. В случае
переполнения системного буфера (например если ``передающая'' программа выдает информацию в канал быстрее чем ее может обработать
``принимающая'' программа) ОС автоматически приостанавливает тот процесс, который осуществляет запись в канал до освобождения буфера.
Наиболее распространенные операторы переадресации
№п/п Синтаксис Описание
1 команда > файл Направляет стандартный поток вывода в новый файл
2 команда 1> файл Направляет стандартный поток вывода в указанный файл
3 команда >> файл Направляет стандартный поток вывода в указанный файл (режим присоединения)
4 команда > файл 2>&1 Направляет стандартные потоки вывода и ошибок в указанный файл
5 команда 2> файл Направляет стандартный поток ошибок в указанный файл
6 команда 2>> файл Направляет стандартный поток ошибок в указанный файл (режим присоединения)
7 команда >> файл 2>&1 Направляет стандартные потоки вывода и ошибок в указанный файл (режим присоединения)
8 команда < файл1 > файл2 Получает входные данные из первого файла и направляет выходные данные во второй файл
9 команда < файл в качестве стандартного входного потока получает данные из указанного файла
10 команда << разделитель Получает данные из стандартного потока ввода до тех пор, пока не встретится разделитель
11 команда <&m В качестве стандартного входного потока получает данные из файла с дескриптором m
12 команда >&m Направляет стандартный поток вывода в файл с дескриптором m
Оператор n>&m позволяет перенаправить файл с дескриптором n туда, куда направлен файл с дескриптором m.
Подобных операторов в командной строке может быть несколько, в этом случае они вычисляются слева направо.
Команда exec и применение дескрипторов файлов
Команда exec заменяет текущий интерпретатор shell указанной командой. Обычно она используется для того, чтобы закрыть
текущий интерпретатор и запустить другой. Но у нее есть и другое применение.
Например, команда вида
exec < файл делает указанный файл стандартным входным потоком всех команд. Выполнять ее в
интерактивном режиме нет смысла — она предназначена для использования в сценариях,
чтобы все идущие после нее команды читали свои входные данные из файла. В этом случае
в конце сценария обязательно должна стоять команда
exec <&– которая закрывает стандартный входной поток (в данном случае файл). Подобный прием применяется
преимущественно в сценариях, выполняющихся при выходе из системы.
Команда exec < файл не только назначает файл стандартным входным потоком всех команд сценария, но и перезаписывает
указатель на файл с дескриптором 0 (stdin). Восстановить этот указатель можно будет только по завершении работы сценария.
Если же в сценарии предполагается продолжить чтение данных с клавиатуры, то необходимо сохранить
указатель на прежний входной поток. Ниже приведен небольшой сценарий, в котором демонстрируется, как это сделать.
$ cat f_desc
#!/bin/bash
exec 3<&0 0<file
read linel
read line2
exec 0<&3
echo $1inel
echo $line2
Первая команда exec сохраняет указатель на стандартный входной поток (stdin) в файле с дескриптором 3
(допускается любое целое число в диапазоне от 3 до 9), а затем открывает файл file для чтения. Следующие две команды read
читают из файла две строки текста. Вторая команда exec восстанавливает указатель на стандартный входной поток: теперь
он связан с файлом stdin, а не file. Завершающие команды echo отображают на экране содержимое прочитанных строк,
которые были сохранены в переменных linel и Iine2.
Результат работы сценария:
$ ./ f_desc
Привет!
Пока!
Синтаксис команд см. в Избранные команды и свойства Unix. или в консоли с помощью man.