$
Встроенная в интерпретатор команда
set
показывает значения всех определенных вами переменных. Для просмотра одной или двух переменных более подходит команда echo
:$ set
HOME=/usr/you
IFS=
PATH=:/usr/you/bin:/bin/:/usr/bin
PS1=$
PS2=>
dir=/usr/you/bin
$ echo $dir
/usr/you/bin
$
Значение переменной связано с той копией интерпретатора, который создал ее, и автоматически не передается процессам — потомкам интерпретатора.
$ x=Hello
Создание x$ sh
Новый shell$ echo $x
Происходит только перевод строки, x не определено в порожденном интерпретаторе
$ ctl-d
Возврат в исходный интерпретатор$ echo $x
Hello
x по-прежнему определено$
Это означает, что в командном файле нельзя изменить значение переменной, поскольку выполнением командного файла управляет порожденный интерпретатор:
$ echo 'x="Good bye"
Создание shell-файла из двух строк…> echo $x' >setx
…для определения и печати x$ cat setx
x="Good Bye"
echo $x
$ echo $x
Hello
x есть Hello в исходном интерпретаторе$ sh setx
Good Bye
x есть Good Bye в порожденном интерпретаторе…$ echo $x
Hello
…но по-прежнему есть Hello в текущем интерпретаторе$
Однако бывают ситуации, когда было бы полезно изменять переменные интерпретатора в командном файле. Очевидным примером является файл, добавляющий новый каталог к вашей переменной
PATH
. Поэтому интерпретатор предоставляет команду '.'
(точка), которая выполняет команды из файла в текущем, а не порожденном интерпретаторе. Первоначально это было задумано для удобства пользователей, чтобы они могли повторно выполнять свой файл .profile
, не входя заново в систему, но в принципе это открывает и другие возможности:$ cat /usr/you/bin/games
PATH=$PATH:/usr/games
Добавим /usr/games к PATH$ echo $PATH
:/usr/you/bin:/bin:/usr/bin
$ . games
$ echo $PATH
:/usr/you/bin:/bin:/usr/bin:/usr/games
$
Поиск файла для команды
'.'
осуществляется с помощью переменной PATH
, так что его можно поместить в ваш каталог bin
.Когда используется команда
'.'
, только условно можно считать, что выполняется командный файл. Файл не "выполняется" в обычном смысле этого слова. Команды из него запускаются, как если бы вы ввели их в диалоговом режиме: стандартный входной поток интерпретатора временно переключается на файл. Поскольку файл читается, не нужно иметь право на его выполнение. Другое отличие состоит в том, что файл не получает аргументов командной строки; $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