you tty2 Sep 28 07:51 rhh tty4 Sep 28 10:02
moh tty5 Sep 28 09:38 ava tty6 Sep 28 10:17
$ cat nu who | wc -l
$ sh < nu
4
$
Результат получился таким же, каким бы он был при задании команды who | wc -l с терминала. Опять-таки, как и большинство программ, интерпретатор берет входной поток из файла, если он указан в качестве аргумента; вы с тем же успехом могли задать:
$ sh nu
Однако досадно вводить "sh" каждый раз; во всяком случае эта запись длиннее и создает различия между программами, написанными, например, на Си, и программами, написанными с помощью shell.[9] Поэтому если файл предназначен для выполнения и если он содержит текст, то интерпретатор считает, что он состоит из команд. Такие файлы называются командными. Все, что вам нужно сделать, это объявить файл nu выполняемым, задав
$ chmod + x nu
а затем вы можете вызывать его посредством
$ nu
С этого момента те, кто используют файл nu, не смогут определить способ его создания.
Способ, с помощью которого интерпретатор на самом деле выполняет nu, сводится к созданию нового процесса интерпретатора, как если бы вы задали
$ sh nu
Этот процесс-потомок называется порожденным интерпретатором, т.е. процессом интерпретатора, возбужденным вашим текущим интерпретатором. Но команда sh nu — это не то же самое, что sh < nu, поскольку в первом случае стандартный входной поток все еще связан с терминалом. Пока команда nu выполняется только в том случае, если она находится в вашем текущем каталоге (при условии, конечно, что текущий каталог включен в PATH, а именно это мы и предполагаем с настоящего момента). Чтобы сделать команду nu частью вашего репертуара независимо от того каталога, с которым вы работаете, занесите ее в свой собственный каталог bin и добавьте /usr/you/bin к списку каталогов поиска:
$ pwd /usr/you
$ mkdir bin Создать bin, если его еще не было
$ echo $PATH Проверить Path, чтобы убедиться
:/usr/you/bin:/bin:/usr/bin Должно быть нечто похожее
$ mv nu bin Установить команду nu в bin
$ ls nu
nu not found Она действительно исчезла
из текущего каталога
$ nu
4 Но интерпретатор ее находит
$
Конечно, ваша переменная PATH должна быть правильно определена в файле .profile, чтобы вам не приходилось переопределять ее при каждом входе в систему.
Существуют и другие простые команды, которые вы можете адаптировать к среде по своему вкусу и создавать таким же способом. Нам показалось удобным иметь следующие команды:
• cs для посылки подходящей последовательности специфических символов с целью очистки экрана вашего терминала (24 символа перевода строки — практически универсальное решение);
• what для запуска who и ps -а, чтобы сообщить, кто работает в системе и что он делает;
• where для вывода идентифицированного названия используемой системы UNIX. Это удобно, если вы постоянно работаете с несколькими версиями. (Установка PS1 служит для подобной цели.)
Просмотрите каталоги /bin и /usr/bin, чтобы выяснить, как много команд являются в действительности командными файлами. Можно ли это сделать с помощью одной команды? Подсказка: посмотрите file(1). Насколько точно предположение, основанное на длине файла?
3.4 Аргументы и параметры команд
Хотя команда nu, как она задумывалась, удовлетворяет своему назначению, многие программы на языке shell могут обрабатывать аргументы, так что при их запуске можно задавать имена файлов и флаги.
Допустим, вы хотите создать программу с именем cx для установки права доступа к файлу на выполнение, так что
$ cx nu
есть сокращенная запись для
$ chmod +x nu
Вы уже знаете почти все, чтобы это сделать. Вам нужен файл cx, содержимое которого суть
chmod +x filename
Единственное, что требуется выяснить — как сообщить команде cx имя файла, так как при каждом запуске cx оно будет иным.
Если интерпретатор выполняет командный файл, то каждое вхождение $1 заменяется первым аргументом, каждое вхождение $2 — вторым и т.д. до $9. Поэтому если файл cx содержит строку
chmod +x $1
то при выполнении команды
$ cx nu
порожденный интерпретатор заменит "$1" на первый аргумент "nu". Рассмотрим всю последовательность операций:
$ echo 'chmod +x $1' >cx Вначале создадим cx
$ sh cx сх Сделать сам файл cx выполняемым
$ echo echo Hi, there! >hello Приготовим тест
$ hello Попробуем
hello: cannot execute
$ cx hello Сделаем файл выполняемым
$ hello Попробуем снова
Hi, there! Работает
$ mv cx /usr/you/bin Установим команду cx
$ rm hello Уберем ненужное
$
Заметьте, что мы задали
$ 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 вообще не получат никаких аргументов. С аргументами или без них команда вызывается правильно: