только условно можно считать, что выполняется командный файл. Файл не "выполняется" в обычном смысле этого слова. Команды из него запускаются, как если бы вы ввели их в диалоговом режиме: стандартный входной поток интерпретатора временно переключается на файл. Поскольку файл читается, не нужно иметь право на его выполнение. Другое отличие состоит в том, что файл не получает аргументов командной строки;
$1
,
$2
и т.д. являются пустыми строками. Было бы неплохо, если бы аргументы передавались, но этого не происходит.
Есть еще один способ установить значение переменной в порожденном интерпретаторе — присвоить его явно в командной строке перед самой командой:
$ echo 'echo $x' >echox
$ cx echox
$ echo $x
Hello
Как и прежде
x не определено в порожденном интерпретаторе
$ x=Hi echox
Hi
Значение x передается порожденному интерпретатору
$
(Первоначально присваивания всюду в командной строке передавались команде, но это противоречило
dd(1)
.)
Операцию
'.'
следует использовать, чтобы навсегда изменить значение переменной, тогда как присваивания в командной строке предназначены для временных изменений. В качестве примера рассмотрим еще раз поиск команд в каталоге
/usr/games
, не указанном в вашей переменной
PATH
:
$ ls /usr/games | grep fort
fortune
Игровая команда fortune
$ fortune
fortune: not found
$ echo $PATH
:/usr/you/bin:/bin:/usr/bin
/usr/games не входит в PATH
$ PATH=/usr/games fortune
Позвони в звонок; закрой книгу; задуй свечу.
$ echo $PATH
:/usr/you/bin:/bin:/usr/bin
PATH не изменилось.
$ cat /usr/you/bin/games
команда games все еще здесь
$ . games
$ fortune
Непродуманная оптимизация - источник всех бед - Кнут
$ echo $PATH
:/usr/you/bin:/bin:/usr/bin:/usr/games
Сейчас PATH изменилось
$
Можно использовать оба средства в одном командном файле. Вы можете несколько видоизменить команду
games
для запуска одной игровой программы без изменения переменной
PATH
или постоянно переопределять
PATH
, чтобы она включала
/usr/games
:
$ cat /usr/you/bin/games
PATH=$PATH:/usr/games $*
Обратите внимание на $*
$ cx /usr/you/bin/games
$ echo $PATH
:/usr/you/bin:/bin:/usr/bin
/usr/games
не входит
$ games fortune
Готов отдать свою правую руку, чтобы одинаково владеть обеими
$ echo $PATH
:/usr/you/bin:/bin:/usr/bin
Все еще не входит
$ . games
$ echo $PATH
:/usr/you/bin:/bin:/usr/bin:/usr/games
Теперь входит
$ fortune
Тот, кто медлит, иногда спасается
$
При первом обращении к games командный файл выполняется в порожденном интерпретаторе, в котором переменная
PATH
временно изменена так, чтобы включать каталог
/usr/games
. В то же время во втором примере файл обрабатывается текущим интерпретатором при значении
$*
, являющемся пустой строкой, поэтому в строке нет команд и переменная
PATH
изменяется. Применение команды
games
в обоих случаях достаточно нетривиально, но в результате получаем удобное и естественное для использования средство.
Для того чтобы значение переменной было доступно в порожденном интерпретаторе, следует использовать команду
export
языка
shell
. (Вы можете поразмышлять о том, почему нет возможности экспортировать значение переменной от порожденного интерпретатора к порождающему его.) Приведем один из рассмотренных выше примеров, но теперь с экспортом переменной:
$ x=Hello
$ export x
$ sh
Новый интерпретатор
$ echo $x
Hello
x доступно в порожденном интерпретаторе
$ x='Good Bye'
Изменим значение x
$ echo $x
Good Bye
$ ctl-d
Выйдем из порожденного интерпретатора
$
Снова в исходном интерпретаторе
$ echo $x
Hello
x по-прежнему Hello
$
Семантика команды
export
нетривиальна, но по крайней мере для повседневных нужд достаточно придерживаться основного правила: никогда не экспортируйте временные переменные, служащие для краткосрочных целей, и всегда экспортируйте переменные, необходимые вам во всех порожденных интерпретаторах (включая, например, интерпретаторы, запускаемые командой
!
редактора
ed
). Поэтому переменные, имеющие специальное значение для интерпретатора, такие, как
PATH
и
НОМЕ
, следует экспортировать.
Упражнение 3.13
Почему в значение переменной
PATH
всегда включается текущий каталог? Куда его нужно поместить?
3.7 Еще раз о переключении ввода-вывода
Понятие стандартного потока диагностики было введено для того, чтобы сообщения об ошибках всегда появлялись на терминале: