$ rm *.save
удалит все файлы, оканчивающиеся на .save.
Заметьте, что все имена файлов выбираются в алфавитном порядке, который отличается от числового. Если в вашей книге 10 глав, порядок может быть не тем, на который вы рассчитываете, поскольку ch10 идет перед ch2:
$ echo *
ch1.1 ch1.2 ... ch10.1 ch10.2 ... ch2.1 ch2.2 ...
Символ * — не единственный способ задания шаблона для интерпретатора shell, хотя и наиболее часто используемый. Шаблон [...] задает любые символы из перечисленных внутри скобок. Несколько подряд следующих букв или цифр можно задать в сокращенном виде:
$ 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.
Упражнение 1.4
В чем состоит различие между следующими командами:
$ 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
$
В дальнейшем мы покажем, как реализуется этот принцип.
Упражнение 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 используются именно таким способом.