6

Я читаю эту книгу об архитектуре bash, и один из сопровождающих bash говорит:

Существуют различные области видимости переменных для вызовов функций оболочки и временные области видимости для переменных, устанавливаемых операторами присваивания, предшествующими команде. Например, когда эти операторы присваивания предшествуют команде, встроенной в оболочку, оболочка должна отслеживать правильный порядок разрешения ссылок на переменные, а связанные области позволяют bash сделать это.

Я не могу понять, как это сделать. Это печатает пустую новую строку:

foo="bar" echo $foo

Это выводит "bar", но переменная foo по-прежнему определяется после завершения команды, поэтому я не считаю ее "областью действия команды":

foo="bar"; echo $foo

Как определить переменную с помощью области действия команды?

2 ответа2

6

Ваше первое предположение было верным, но вы использовали плохой пример.  Когда оболочка читает команду

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 (если оно есть), когда возвращается к своему первичному входу (терминалу).

5

Проблема здесь в том, что расширение переменной ($foo → value) происходит до оценки всей команды (поместите foo=bar в среду, запустите echo ...).

Это будет работать для команд, которые сами обращаются к среде:

foo=bar env | grep ^foo

foo=bar declare -p foo

У Bash на самом деле нет достаточного объема для того, что вы ищете; вам нужно будет использовать трюк "подпроцесс", чтобы получить новый процесс для команды. (Конечно, это означает, что область доступна только для чтения, никакие изменения не достигнут родителя ...) Используйте ( ... ) для создания подоболочки:

(foo=bar; echo $foo)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .