Задает с
буквально a|b
Только для выражений выбора; задает а
или b
/
Для имен файлов; соответствует только символу /
в выражении; для выражений выбора сопоставляется, как любой другой символ .
Если это первый символ в имени файла, то сопоставляется только с явно заданной точкой в выражении
Таблица 5.2: Правила сопоставления шаблонов в интерпретаторе
Два последних варианта второго оператора
case
относятся к случаю, когда единственный аргумент может быть годом; напомним, что в первом операторе case
предполагалось, что аргументом является месяц. Если это число, которым может быть задан месяц, то ничего не происходит (иначе предполагается, что задан год).Наконец, в последней строке вызывается
/usr/bin/cal
(настоящая команда cal
) с преобразованными аргументами. Наша версия команды cal
работает так, как этого мог бы ожидать начинающий:$ date
Sat Oct 1 06:09:55 EDT 1983
$ cal
October 1983
S М Tu W Th F S
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
$ cal dec
December 1983
S M Tu W Th F S
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
$
При обращении к
cal 1984
будет напечатан календарь на весь 1984 год. Наша обобщенная команда cal
выполняет то же задание, что и исходная, но более простым и легко запоминающимся способом. Поэтому мы предпочитаем называть ее cal
, а не calendar
(что уже является командой), или как-нибудь еще с менее простой мнемоникой, например ncal
. При использовании одного и того же имени пользователю не придется вырабатывать новые рефлексы для печати календаря.Прежде чем завершить обсуждение оператора
case
, следует объяснить, почему правила сопоставления шаблонов в интерпретаторе отличаются от правил для редактора ed
и его производных. Действительно, наличие двух видов шаблонов означает, что нужно изучать два набора правил и иметь два программных фрагмента для их обработки. Некоторые различия вызваны просто неудачным выбором, который никогда не был зафиксирован. В частности, нет никаких причин (кроме того, что так сложилось исторически), по которым ed
использует '.'
а интерпретатор — '?'
для задания единственного символа. Но иногда шаблоны применяются по-разному. Регулярные выражения в редакторе используются для поиска последовательности символов, которая может встретиться в любом месте строки; специальные символы и $ нужны, чтобы направить поиск с начала или конца строки. Но для имен файлов мы хотим, чтобы направление поиска определялось по умолчанию, поскольку это наиболее общий случай. Было бы неудобным задавать нечто вроде$ ls ^?*.с$
Так не получитсявместо
$ ls *.с
Упражнение 5.1Если пользователи предпочтут вашу версию команды
cal
, как бы вы сделали ее общедоступной? Что следует предпринять, чтобы поместить ее в /usr/bin
?Упражнение 5.2Имеет ли смысл сделать так, чтобы при обращении
cal 83
был напечатан календарь за 1983 г.? Как в этом случае задать вывод календаря?Упражнение 5.3Модифицируйте команду
cal
так, чтобы можно было задавать больше одного месяца, например:$ cal oct nov
и даже диапазон месяцев:
$ cal oct-dec
Если сейчас декабрь, а вы выполняете обращение
cal jan
, то какой должен быть напечатан календарь: на январь этого года или следующего? Когда следует прекратить расширять возможности команды cal
?5.2 Что представляет собой команда which
?
При обзаведении собственными версиями команд, аналогичных
cal
, возникает ряд трудностей. В частности, когда вы работаете как пользователь Мэри и вошли в систему под именем mary
, то, вводя команду cal
, получаете стандартную версию команды вместо новой, если, конечно, не установили в своем каталоге bin
связь с новой командой cal
. Это может привести к путанице: вспомните, что сообщения об ошибках в исходной, команде cal
не очень вразумительны. Мы привели всего лишь один пример возникающих трудностей. Поскольку интерпретатор осуществляет поиск команд среди каталогов, задаваемых переменной PATH
, всегда есть вероятность столкнуться не с той версией команды, которую вы ожидали. Например, если вы задали команду, скажем echo
, имя выполняемого на самом деле файла будет ./echo
, /bin/echo
, /usr/bin/echo
или какое-то другое в зависимости от компонентов вашей переменной PATH
и от того, где находятся файлы. Может случиться, что в вашей последовательности поиска ранее, чем вы ожидали, окажется выполняемый файл с правильным именем, но не с теми результатами. Наиболее типичным примером в такой ситуации является команда test
, которую мы обсудим позднее. Ее название настолько распространено для временной версии программы, что вызовы "не тех" команд test
происходят раздражающе часто[12]. Здесь весьма полезным средством явилась бы команда, которая помогла бы выяснить, какая версия программы должна выполняться.Один из вариантов решения — цикл поиска по каталогам, указанным в
PATH
, выполняемого файла с данным именем. В гл. 3 мы использовали цикл for
по именам файлов и аргументам. Здесь же нужен такой цикл:for i in компонента в PATH
do
если заданное имя в каталоге i
печать полного путевого имени
done
Поскольку любую команду можно запустить внутри символов слабого ударения очевидное решение состоит в том, чтобы запустить
sed
по значению PATH
, заменив двоеточия на пробелы. Мы можем проверить это с помощью нашего старого друга echo
:$ echo $PATH
:/usr/you/bin:/bin:/usr/bin
4 компонента$ echo $PATH | sed 's/:/ /a'
/usr/you/bin /bin /usr/bin
Только три выдано!$ echo `echo $PATH | sed 's/:/ /g'`
/usr/you/bin /bin /usr/bin
По-прежнему только три$
Однако такое решение проблематично. Пустая строка в
PATH
служит синонимом '.'
. Поэтому перевод двоеточий в пробелы не слишком удачен — теряется информация о пустых компонентах. Для создания правильного списка каталогов пустую компоненту PATH
нужно перевести в точку. Пустая компонента может быть в середине, начале или конце строки, так что вам придется потрудиться, чтобы учесть все возможные случаи:$ echo $PATH | sed 's/^:/./
> s/::/:.:/g
>