UNIX — универсальная среда программирования - Керниган Брайан Уилсон
$
Заметьте, что мы задали
$ sh cx сх
в точности так, как сделал бы автоматически интерпретатор, если бы cx была выполняемой и можно было бы задать
$ cx сх
А как быть, если нужно работать с несколькими аргументами, например, заставить программу cx воздействовать сразу на несколько файлов? Прямолинейное решение состоит в том, чтобы включить девять аргументов в командный файл:
chmod +x $1 $2 $3 $4 $5 $6 $7 $8 $9
(Это годится только для девяти аргументов, так как конструкция $10 распознается как "первый аргумент, за которым следует 0"!) Если пользователь такого командного файла задаст меньше девяти аргументов, то недостающие окажутся пустыми строками. Это приведет к тому, что только настоящие аргументы будут переданы chmod порожденным интерпретатором. Такое решение, конечно, приемлемо, но не вполне корректно и не подходит для случая с числом аргументов более девяти.
С учетом упомянутой выше трудности интерпретатор предоставляет сокращенную запись $*, означающую "все аргументы". В этом случае правильно определить cx:
chmod +x $*
что является эффективным при любом числе аргументов.
Используя $* в своем репертуаре, вы можете создать некоторые полезные командные файлы, такие, как lc или m:
$ cd /usr/you/bin
$ cat lc
#lc: подсчет числа строк в файлах
wc -l $*
$ cat m
#m: точный способ послать почту
mail $*
$
Обе команды можно осмысленно использовать и без аргументов. Если нет аргументов, $* будет пустым, и wc и mail вообще не получат никаких аргументов. С аргументами или без них команда вызывается правильно:
$ lc /usr/you/bin/*
1 /usr/you/bin/cx
2 /usr/you/bin/lc
2 /usr/you/bin/m
1 /usr/you/bin/nu
2 /usr/you/bin/what
1 /usr/you/bin/where
9 total
$ ls /usr/you/bin | lc
6
$
Эти и другие команды, описываемые в настоящей главе, являются командами пользователя, т.е. вы создаете их для себя и помещаете в свой каталог /bin, поэтому вряд ли они должны стать общедоступными. В гл. 5 мы исследуем вопрос создания общедоступных программ на языке shell.
Аргументами командного файла не обязательно должны быть имена файлов. Рассмотрим в качестве примера поиск в каталоге, где хранится личный телефонный справочник. Если у вас есть файл с именем /usr/you/lib/phone-book, содержащий строки следующего вида:
dial-a-joke 212-976-3838
dial-a-prayer 212-246-4200
dial santa 212-976-3636
dow jones report 212-976-4141
то для поиска в нем можно воспользоваться командой grep. (Ваш собственный каталог lib — хорошее хранилище таких частных баз данных.) Поскольку команда grep не определяет формат информации, можно искать имена, адреса, индексы или еще какие-нибудь нужные вам сведения. Составим справочную программу для каталога, которой дадим имя 411 по номеру одной из телефонных справочных служб:
$ echo 'grep $* /usr/you/lib/phone-book' > 411
$ cx 411
$ 411 joke
dial-a-joke 212-976-3838
$ 411 dial
dial-a-joke 212-976-3838
dial-a-prayer 212-246-4200
dial santa 212-976-3636
$ 411 'dow jones'
grep: can't open jones Что-то не так
$
Последний пример вскрывает потенциальную проблему: хотя dow jones представляет для команды 411 единый аргумент, он содержит пробел и уже не заключен в апострофы, поэтому порожденный интерпретатор, выполняющий команду 411, преобразует его в два аргумента для grep, как если бы вы задали
$ grep dow jones /usr/you/lib/phone-book
что, очевидно, неверно.
Один из возможных путей обойти эту проблему основан на том, как интерпретатор трактует кавычки. Хотя все, что заключено в '...', не затрагивается, интерпретатор "заглядывает" внутрь "..." в поиске комбинаций с $, , `...`. Поэтому если изменить команду 411 следующим образом:
$ grep "$*" /usr/you/lib/phone-book
то $* заменяется на аргументы, но команде grep передается как один аргумент, даже при наличии пробелов:
$ 411 dow jones
dow jones report 212-976-4141
$
Кстати, можно сделать с помощью флага -y команду grep (а значит, и 411) независимой от использования строчных или прописных букв:
$ grep -y pattern ...
При наличии флага -y строчные буквы из шаблона могут сопоставляться с прописными буквами из входного потока. (Такой флаг есть в седьмой версии, но отсутствует в других системах.)
Более подробно аргументы команд мы рассмотрим в гл. 5, но одно важное замечание необходимо сделать здесь. Аргумент $0 — это имя выполняемой программы; в случае cx $0 есть "cx". Новое применение $0 находит в реализации программ 2, 3, 4, …, которые печатают свой выходной поток в несколько столбцов: