Программа обычно ценна тем, что может обрабатывать данные:
принимать одно, на выходе выдавать другое, причём в качестве
данных может выступать практически что угодно: текст, числа,
звук, видео... Потоки входных и выходных данных для команды
называются ввод и
вывод. Потоков ввода и вывода у каждой
программы может быть и по несколько. В Linux
каждый процесс
при создании в обязательном порядке получает так называемые
стандартный ввод (standard input, stdin)
и стандартный вывод (standard output,
stdout) и стандартный вывод ошибок
(standard error, stderr).
Стандартные потоки ввода/вывода предназначены в первую очередь для обмена текстовой информацией. Тут даже не важно, кто общается с помощью текстов: человек с программой или программы между собой — главное, чтобы у них был канал передачи данных и чтобы они говорили «на одном языке».
Текстовый принцип работы с машиной позволяет отвлечься от
конкретных частей компьютера, вроде системной клавиатуры и
видеокарты с монитором, рассматривая единое
оконечное устройство, посредством которого
пользователь вводит текст (команды) и передаёт его системе, а
система выводит необходимые пользователю данные и сообщения
(диагностику и ошибки). Такое устройство называется
терминалом. В общем случае терминал — это точка входа пользователя в систему, обладающая
способностью передавать текстовую информацию. Терминалом может
быть отдельное внешнее устройство, подключаемое к компьютеру
через порт последовательной передачи данных (в персональном
компьютере он называется «COM port»). В роли
терминала может работать (с некоторой поддержкой со стороны
системы) и программа (например, xterm или ssh). Наконец,
виртуальные консоли Linux
— тоже терминалы,
только организованные программно с помощью подходящих устройств
современного компьютера.
При работе с командной строкой, стандартный ввод командной оболочки связан с клавиатурой, а стандартный вывод и вывод ошибок — с экраном монитора (или окном эмулятора терминала). Покажем на примере простейшей команды — cat. Обычно команда cat читает данные из всех файлов, которые указаны в качестве её параметров, и посылает считанное непосредственно в стандартный вывод (stdout). Следовательно, команда
/home/larry/papers# cat history-final masters-thesis
выведет на экран сначала содержимое файла
history-final
, а затем — файла
masters-thesis
.
Однако если имя файла не указано, программа cat читает входные данные из stdin и немедленно возвращает их в stdout (никак не изменяя). Данные проходят через cat, как через трубу. Приведём пример:
/home/larry/papers# cat Hello there. Hello there. Bye. Bye. Ctrl-D/home/larry/papers#
Каждую строчку, вводимую с клавиатуры, программа cat немедленно возвращает на экран. При вводе информации со стандартного ввода конец текста сигнализируется вводом специальной комбинации клавиш, как правило Ctrl-D.
Приведём другой пример. Команда sort читает строки вводимого текста (также из stdin, если не указано ни одного имени файла) и выдаёт набор этих строк в упорядоченном виде на stdout. Проверим её действие.
/home/larry/papers# sort bananas carrots apples Ctrl+D apples bananas carrots /home/larry/papers#
Как видно, после нажатия Ctrl-D, sort вывела строки упорядоченными в алфавитном порядке.
Допустим, вы хотите направить вывод команды sort в некоторый
файл, чтобы сохранить упорядоченный по алфавиту список на диске.
Командная оболочка позволяет перенаправить
стандартный вывод команды в файл, используя символ
>
. Приведём пример:
/home/larry/papers# sort > shopping-list bananas carrots apples Ctrl-D/home/larry/papers#
Можно увидеть, что результат работы команды sort не
выводится на экран, однако он сохраняется в файле с именем
shopping-list
. Выведем на экран содержимое
этого файла:
/home/larry/papers# cat shopping-list apples bananas carrots /home/larry/papers#
Пусть теперь исходный неупорядоченный список находится в
файле items
. Этот список можно упорядочить
с помощью команды sort, если указать ей, что
она должна читать из данного файла, а не из своего стандартного
ввода, и кроме того, перенаправить стандартный вывод в файл, как
это делалось выше. Пример:
/home/larry/papers# sort items shopping-list /home/larry/papers# cat shopping-list apples bananas carrots /home/larry/papers#
Однако можно поступить иначе, перенаправив не только
стандартный вывод, но и стандартный ввод утилиты из
файла, используя для этого символ <
:
/home/larry/papers# sort < items apples bananas carrots /home/larry/papers#
Результат команды sort < items
эквивалентен команде sort items, однако
первая из них демонстрирует следующее: при выдаче команды
sort < items система ведёт себя так, как
если бы данные, которые содержатся в файле
items
, были введены со стандартного ввода.
Перенаправление осуществляется командной оболочкой. Команде
sort не сообщалось имя файла
items
: эта команда читала данные из своего
стандартного ввода, как если бы мы вводили их с
клавиатуры.
Введём понятие фильтра. Фильтром является программа, которая читает данные из стандартного ввода, некоторым образом их обрабатывает и результат направляет на стандартный вывод. Когда применяется перенаправление, в качестве стандартного ввода и вывода могут выступать файлы. Как указывалось выше, по умолчанию, stdin и stdout относятся к клавиатуре и к экрану соответственно. Программа sort является простым фильтром — она сортирует входные данные и посылает результат на стандартный вывод. Совсем простым фильтром является программа cat — она ничего не делает с входными данными, а просто пересылает их на выход.
Выше уже демонстрировалось, как использовать программу sort в качестве фильтра. В этих примерах предполагалось, что исходные данные находятся в некотором файле или что эти исходные данные будут введены с клавиатуры (стандартного ввода). Однако как поступить, если вы хотите отсортировать данные, которые являются результатом работы какой-либо другой команды, например, ls?
Будем сортировать данные в обратном алфавитном порядке; это
делается опцией -r
команды
sort. Если вы хотите перечислить файлы в
текущем каталоге в обратном алфавитном порядке, один из способов
сделать это будет таким. Применим сначала команду ls:
/home/larry/papers# ls english-list history-final masters-thesis notes /home/larry/papers#
Теперь перенаправляем выход команды ls в файл с именем file-list
/home/larry/papers# ls > file-list /home/larry/papers# sort -r file-list notes masters-thesis history-final english-list /home/larry/papers#
Здесь выход команды ls сохранен в файле, а после этого
этот файл был обработан командой sort
-r
. Однако этот путь является
неизящным и требует использования временного файла для хранения
выходных данных программы ls.
Решением в данной ситуации может служить создание
состыкованных команд (pipelines).
Стыковку осуществляет командная оболочка, которая stdout первой
команды направляет на stdin второй команды. В данном случае мы
хотим направить stdout команды ls на stdin команды
sort. Для стыковки используется символ
|
, как это показано в следующем примере:
/home/larry/papers# ls | sort -r notes masters-thesis history-final english-list /home/larry/papers#
Эта команда короче, чем совокупность команд, и её проще набирать.
Рассмотрим другой полезный пример. Команда
/home/larry/papers# ls /usr/bin
выдаёт длинный список файлов. Большая часть этого списка пролетает по экрану слишком быстро, чтобы содержимое этого списка можно было прочитать. Попробуем использовать команду more для того, чтобы выводить этот список частями:
/home/larry/papers# ls /usr/bin | more
Теперь можно этот список «перелистывать».
Можно пойти дальше и состыковать более двух команд. Рассмотрим команду head, которая является фильтром следующего свойства: она выводит первые строки из входного потока (в нашем случае на вход будет подан выход от нескольких состыкованных команд). Если мы хотим вывести на экран последнее по алфавиту имя файла в текущем каталоге, можно использовать следующую длинную команду:
/home/larry/papers# ls | sort -r | head -1 notes /home/larry/papers\#
где команда head -1
выводит на экран первую строку получаемого ей входного потока
строк (в нашем случае поток состоит из данных от команды ls),
отсортированных в обратном алфавитном порядке.
Эффект от использования символа >
для
перенаправления вывода файла является деструктивным; иными
словами, команда
/home/larry/papers# ls > file-list
уничтожит содержимое файла file-list
,
если этот файл ранее существовал, и создаст на его месте новый
файл. Если вместо этого перенаправление будет сделано с помощью
символов >>
, то вывод будет приписан в
конец указанного файла, при этом исходное содержимое файла не
будет уничтожено. Например, команда
/home/larry/papers# ls >> file-list
приписывает вывод команды ls в конец файла
file-list
.
Следует иметь в виду, что
перенаправление ввода и вывода и стыкование команд
осуществляется командными оболочками, которые поддерживают
использование символов >
, >>
и
|
. Сами команды не способны воспринимать и
интерпретировать эти символы.