Ваше первое предположение было верным, но вы использовали плохой пример.
Когда оболочка читает команду
foo=bar echo $foo
первое, что он делает (или, по крайней мере, одно из первых), это ищет ссылки на переменные (например, $foo
) и оценивает их.
Затем он обрабатывает то, что осталось от линии.
(Это может быть немного упрощением; подробнее см. bash(1)
или Справочное руководство Bash .)
Итак, у вас есть команда
echo (nothing)
работает с foo=bar
; но уже слишком поздно; там ничего не осталось, чтобы посмотреть на значение $foo
.
Вы можете продемонстрировать это с помощью следующей последовательности:
$ foo=oldvalue
$ foo=bar echo "$foo"
oldvalue
Но
foo=bar command
это путь. Несколько примеров, которые работают:
foo=bar sh -c 'echo "$foo"'
а также
foo=bar env
(Вы можете хотеть передать это через grep foo
.)
Я только что заметил предложение, которое вы цитировали:«Когда эти операторы присваивания предшествуют команде, встроенной в оболочку, например,…», предполагая, что встроенные команды (такие как echo
) представляют собой особый случай.
Интуитивно понятно (по крайней мере для меня), что эта «область команд», которую вы ищете, должна работать, устанавливая переменную среды в дочернем процессе, и неясно, как она будет работать для встроенной команды, который не работает в дочернем процессе.
Немногие встроенные команды обращаются к среде напрямую, и их взаимодействие с переменными оболочки иногда является загадочным.
Но я придумал еще пару примеров, которые могут быть больше, чем вы ищете:
foo=bar eval 'echo $foo'
будет отображаться «bar», потому что оценка $foo
отложена.
Он обрабатывается командой eval
(встроенной), а не начальным этапом синтаксического анализа оболочки.
Или создайте текстовый файл с именем (например) showme.sh
.
Вставьте в него команду echo $foo
(или echo "$foo"
) и скажите
foo=bar . showme.sh
Это, вероятно, то, о чем говорит ваша книга, когда говорится: «… оболочка должна отслеживать правильный порядок разрешения ссылок на переменные…».
Каким-то образом оболочка выполняет команды в showme.sh
с foo
равным bar
, и затем возвращается к предыдущему значению foo
(если оно есть), когда возвращается к своему первичному входу (терминалу).