Большинство команд, которые мы рассматривали, производят вывод на терминал, некоторые из них, подобно редактору, осуществляют ввод с терминала. А теперь приведем почти универсальное правило: терминал может быть заменен для ввода, вывода или обеих операций на файл.
Например,
$ ls
выдает список файлов на ваш терминал. Но если задать
$ ls > filelist
то тот же список файлов помещается вместо этого в файл
filelist
. Символ >
означает, что выходной поток должен быть помещен в указанный далее файл, а не выведен на терминал. Файл будет создан, если он ранее не существовал, или будет заменено содержимое старого. На своем терминале вы ничего не получите. В качестве другого примера можно слить несколько файлов, "перехватив" выходной поток команды cat
и направив его в файл:$ cat f1 f2 f3 > temp
Символ
>>
действует подобно >
, но указывает на необходимость добавить выходной поток к концу файла. Значит, команда$ cat f1 f2 f3 >> temp
сольет содержимое
f1
, f2
, f3
и добавит результат в конец temp
, вместо того чтобы затереть его старое содержимое. Так же как и для операции >
, если файл temp
не существует, то он будет создан первоначально пустым.Аналогично символ
<
означает, что входной поток программы берется из последующего файла, а не с терминала. Так, можно заготовить письмо в файле let
, а затем послать его нескольким адресатам:$ mail mary joe torn bob < let
Во всех этих примерах наличие пробелов по обе стороны символа
>
или <
не обязательно, но такое представление традиционно.Имея возможность переключать выходной поток с помощью
<
, мы можем комбинировать команды, получая эффект, недостижимый другим способом. Например, можно выдать список пользователей в алфавитном порядке$ who > temp
$ sort < temp
Поскольку команда
who
выдает по одной строке на каждого пользователя, работающего в системе, a wc -l
производит подсчет строк (подавляя вывод числа слов и символов), можно подсчитать число пользователей с помощью команд:$ who > temp
$ wc -l < temp
и число файлов в текущем каталоге:
$ ls > temp
$ wc -l < temp
хотя в это число войдет и сам файл
temp
. Можно выдать список имен файлов в три столбца, задав$ ls > temp
$ pr -3 < temp
Наконец, можно убедиться в том, что некий пользователь вошел в систему, комбинируя команды
who
и grep
:$ who > temp
$ grep mary < temp
Во всех перечисленных выше примерах, как и в случае имен файлов, содержащих образы типа
*
, важно понимать, что символы <
и >
обрабатываются самим интерпретатором shell
, а не отдельной программой. Благодаря этому переключение входного и выходного потоков возможно для любой программы, причем сама программа даже "не подозревает", что происходит что-то необычное.Изложенное подводит нас к важному выводу. Команда
$ sort < temp
сортирует содержимое файла
temp
так же, как$ sort temp
но в их действиях есть различие. Поскольку строка
< temp
обрабатывается интерпретатором shell
, первая команда sort
не воспринимает файл temp
как свой аргумент; она просто сортирует собственный стандартный входной поток, который переключен интерпретатором на файл temp
. В то же время в последнем случае имя temp передается команде sort в качестве аргумента, она читает его и сортирует файл. Команде sort можно передать список файлов:$ sort temp1 temp2 temp3
но, если имена файлов отсутствуют, она всегда будет сортировать стандартный входной поток. Это существенная особенность большинства команд: если не указаны имена файлов, то обрабатывается стандартный входной поток. Следовательно, достаточно ввести имя команды, чтобы посмотреть, как она выполняется. Например,
$ sort
ghi
abc
def
ctl-c
abc
def
ghi
$
В дальнейшем мы покажем, как реализуется этот принцип.
Упражнение 1.5Объясните, почему команда
$ ls > ls.out
включает
ls.out
в список имен.Упражнение 1.6Объясните результат выполнения команды
$ wc temp > temp
Что произойдет, если вы ошибетесь в имени команды, задав
$ woh > temp
Программные каналыВсе примеры, приведенные в конце предыдущего раздела, основаны на одном и том же приеме: выходной поток одной программы передается в качестве входного потока для другой программы через временный файл. Сам временный файл больше не имеет никакого смысла; в самом деле, неудобно использовать такой файл. Это соображение привело к возникновению одной из фундаментальных концепций системы UNIX, идеи программного канала. Программный канал представляет собой средство связи выходного потока одной программы с входным потоком другой без всяких временных файлов; соединение программным каналом двух или более программ называется конвейером.
Пересмотрим теперь некоторые из предыдущих примеров с точки зрения использования программных каналов вместо временных файлов. Вертикальная черта служит указанием интерпретатору
shell
для создания конвейера:$ who | sort
Печать отсортированного списка пользователей$ who | wc -l
Подсчет числа пользователей$ ls | wc -l
Подсчет числа файлов$ ls | pr -3
Вывод списка имен файлов в три столбца$ who | grep mary
Поиск определенного пользователяВсякая программа, вводящая информацию с терминала, может вводить ее и по программному каналу; всякая программа, производящая вывод на терминал, может выдавать информацию в программный канал. Это тот случай, когда приносит плоды решение читать стандартный входной поток, если не заданы никакие файлы. Любая программа, выполняющая данное соглашение, может быть включена в конвейер. В рассмотренных выше примерах команды
pr
, grep
, sort
и wc
используются именно таким способом.Можно связать конвейером сколь угодно много программ. Например,
$ ls | pr -3 | lpr
создает список имен файлов в три столбца и выдает его на печатающее устройство, а
$ who | grep mary | wc -l
подсчитывает, сколько раз пользователь Мэри входила в систему.
Программы, связанные конвейером, выполняются одновременно, а не последовательно одна за другой. Это означает, что программы в конвейере могут вступать в диалог; ядро выполняет необходимые операции переключения и синхронизации, чтобы такая схема работала. Большинство команд следует определенному образцу, поэтому они хорошо вписываются в конвейер и могут выполняться в нем на любом месте. Обычный вызов команды имеет вид:
команда флаги возможные имена файлов
Если имена файлов не указаны, то команда читает стандартный входной поток, который по умолчанию поступает с терминала (что удобно для экспериментирования), однако возможно его переключение на файл или программный канал. Кроме того, во многих командах выдача идет в стандартный выходной поток, который по умолчанию направлен на терминал, но его также можно переключить на файл или программный канал.
Сообщения же об ошибках, выдаваемые командами, следует обрабатывать по-другому, иначе они затеряются в файле или программном канале. Поэтому каждая команда имеет еще один стандартный файл, называемый фа