$ pr ch[12346789]* Печать глав 1,2,3,4,6,7,8,9, но не 5
$ pr ch[1-46-9]* То же самое
$ rm temp[a-z] Удалить все tempa, …, tempz
Шаблон ? задает любой одиночный символ:
$ ls ? Список файлов с именем из одного символа
$ ls -l ch?.1 Список ch1.1 ch2.1 ch3.1 и т.д., но не ch10.1
$ rm temp? Удалить все файлы temp1, …, tempa и т.д.
Отметим, что шаблоны сопоставляются только с именами существующих файлов. В частности, нельзя создать новые имена файлов с помощью шаблонов. Например, если вы захотите расширить ch до chapter в каждом имени файла, то такой вариант вам не поможет:
$ mv ch.* chapter.* Не работает!
поскольку chapter.* не соответствует ни одному из существующих имен файлов.
Символы шаблонов, подобные *, могут использоваться в абсолютных именах наравне с обычными именами файлов; сопоставление происходит для каждого компонента абсолютного имени, содержащего специальный символ. Так, /usr/mary/* инициирует поиск файлов в /usr/mary/, a /usr/*/calendar порождает список абсолютных имен всех пользователей, работающих с каталогом calendar.
Если вам когда-нибудь придется отказаться от специального назначения символов *, ? и др., заключите весь аргумент в апострофы, например:
$ ls '?'
Можно также предварить специальный символ обратной дробной чертой:
$ ls \?
(Вспомните, что, поскольку ? не является символом стирания или уничтожения, обратная дробная черта перед ним будет обрабатываться не ядром, а интерпретатором shell.) Использование кавычек подробно рассматривается в гл. 3.
В чем состоит различие между следующими командами:
$ ls junk $ echo junk
$ ls / $ echo /
$ ls $ echo
$ ls * $ echo *
$ ls '*' $ echo '*'
Большинство команд, которые мы рассматривали, производят вывод на терминал, некоторые из них, подобно редактору, осуществляют ввод с терминала. А теперь приведем почти универсальное правило: терминал может быть заменен для ввода, вывода или обеих операций на файл.
Например,
$ 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
$
В дальнейшем мы покажем, как реализуется этот принцип.
Объясните, почему команда
$ ls > ls.out
включает ls.out в список имен.
Объясните результат выполнения команды
$ wc temp > temp
Что произойдет, если вы ошибетесь в имени команды, задав
$ woh > temp
Все примеры, приведенные в конце предыдущего раздела, основаны на одном и том же приеме: выходной поток одной программы передается в качестве входного потока для другой программы через временный файл. Сам временный файл больше не имеет никакого смысла; в самом деле, неудобно использовать такой файл. Это соображение привело к возникновению одной из фундаментальных концепций системы UNIX, идеи программного канала. Программный канал представляет собой средство связи выходного потока одной программы с входным потоком другой без всяких временных файлов; соединение программным каналом двух или более программ называется конвейером.