Странное расширение переменных оболочки в bash

Вопрос или проблема

Руководство по bash говорит: “Окружение для любой простой команды или функции может быть временно дополнено путем присвоения ей параметров с префиксом.”
Я также понимаю, что экспортируемые переменные по умолчанию передаются в подпроцессы, которые создает bash.
Я тестирую некоторые поведения с неэкспортируемыми переменными, и я не понимаю, как это работает, когда после присвоения следует оператор ‘;’, а затем выполняются другие команды.

Мой случай следующий:

VAR=hello; echo $VAR печатает “hello”.

VAR=hello :; echo $VAR печатает пустую строку.

VAR=hello; echo $VAR; bash -c 'echo $VAR' печатает “hello” и пустую строку.

Вопрос в том, почему в первой и третьей командах VAR разворачивается? Это разные команды, без (по-видимому) присвоений параметров с префиксом.

PS: Я пробовал в bash 4.4.20 и 5.1.16, поведение одинаковое в обеих версиях.

Кажется, что вы в основном спрашиваете об экспорте и о том, когда что-то нужно экспортировать. Давайте рассмотрим каждый из ваших примеров:

  1. VAR=hello; echo $VAR: это две команды, выполняются в одной и той же сессии оболочки. Поскольку мы находимся в одной сессии, первое присвоение переменной достаточно, и нет необходимости ничего экспортировать.

  2. VAR=hello :; echo $VAR: здесь тоже у нас две команды в одной сессии оболочки, но в данном случае переменная была явно установлена только на время выполнения команды :. Таким образом, вы не установили переменную в вашей сессии оболочки, вы установили ее только для этой одной команды. Поэтому, когда вы возвращаетесь в оболочку, переменная не задана, и echo печатает пустую строку.

  3. VAR=hello; echo $VAR; bash -c 'echo $VAR': здесь у нас одна сессия оболочки, в которой вы выполняете VAR=hello и echo $VAR. Затем вы запускаете новую сессию оболочки, которая не наследует неэкспортируемые переменные, и в этой второй сессии echo $VAR ничего не печатает. Здесь экспортирование могло бы сделать разницу:

    $ var=hello; bash -c 'echo $var'
    
    $ export var=hello; bash -c 'echo $var'
    hello
    

Ikkachu сделал очень хорошее замечание в удаленном сейчас комментарии, который я воспроизвожу ниже:

Хотя так как : — это специальная встроенная команда, назначение в VAR=hello : должно быть по POSIX видно в следующей среде оболочки. Bash этого в обычном режиме не делает, но почти любая другая POSIX-совместимая оболочка сделает это, и bash в POSIX-режиме тоже. Так что $shell -c 'unset VAR; VAR=hello :; echo "$VAR"' действительно печатает hello для таких оболочек, как bash -o posix, dash или ksh. Это было бы иначе с, например, true вместо :, так как это простая команда.

Ответ или решение

Вопрос о странном расширении переменных оболочки в Bash требует глубокого понимания механизмов, которые управляют передачей переменных между сессиями оболочки и их воздействием на окружение команд. Давайте разберем это явление, используя методологию TEA, состоящую из Теории, Примеров и Применения.

Теория

В Bash переменные могут передаваться в среду выполнения команд через экспорт или одноразовое связывание с командой. Экспортированные переменные по умолчанию наследуются дочерними процессами, созданными Bash. Однако поведение локальных (неэкспортированных) переменных зависит от контекста их использования.

Основные положения:

  1. Экспорт переменных: Переменные, экспортированные командой export, становятся частью среды и доступны всем дочерним процессам.
  2. Локальные переменные: Они видны только в текущей оболочке и не передаются в дочерние процессы, если не экспортированы.
  3. Присваивание переменных для команд: Переменные могут временно связываться с командой, если они предшествуют вызову этой команды. Это связывание лимитировано временем выполнения команды и не сохраняется после её завершения.

Примеры

Рассмотрим предоставленные случаи:

  1. VAR=hello; echo $VAR: Здесь две команды выполняются в одном сеансе оболочки. Переменная VAR присваивается значению hello, и это значение используется в команде echo. Поскольку команды выполняются последовательно в одной и той же среде, VAR доступен при выполнении echo.

  2. VAR=hello :; echo $VAR: В этом случае оператор : — это встроенная команда, которая ничего не делает, но служит как точка выполнения. Переменная VAR временно присваивается этой команде. После завершения :, VAR не сохраняется в сессии оболочки и поэтому echo $VAR выводит пустую строку.

  3. VAR=hello; echo $VAR; bash -c 'echo $VAR': Здесь снова есть последовательное выполнение команд. VAR=hello и echo $VAR выполняются в текущей сессии, где VAR доступно, поэтому echo выводит hello. Однако bash -c 'echo $VAR' запускает новую оболочку, где переменная VAR не экспортирована и, следовательно, недоступна, что приводит к выводу пустой строки.

Применение

Для эффективного управления переменными в скриптах Bash важно понимать принцип их наследования и видимости:

  • Экспортируйте переменные, если они должны быть доступны в дочерних процессах. Это особенно важно для сложных скриптов, чтобы поддерживать консистентность данных между различными частями программы.

  • Используйте временное присваивание, когда переменные нужны исключительно для конкретной команды, чтобы избегать загрязнения глобального пространства переменных.

  • Разрабатывайте скрипты с учётом окружения, в котором они выполняются. Например, включение POSIX-совместимого режима может изменить поведение относительных к именным переменным механизмов в Bash.

Важное замечание

Как было подсказано в удаленном комментарии на форуме Stack Exchange, : является специальной встроенной командой, что означает, что присваивание переменных этой командой может быть видимо в последующей среде в других оболочках POSIX, таких как dash или ksh. Bash не ведёт себя таким образом в обычном режиме, но делает это в POSIX-совместимом режиме. Это важно учитывать при разработке скриптов, которые должны быть портативными и совместимыми с различными оболочками.

Таким образом, управление переменными в Bash — это вопрос понимания их области видимости и применения в контексте выполнения команд. Следуя описанным рекомендациям, можно обеспечить корректную работу скриптов и их предсказуемое поведение.

Оцените материал
Добавить комментарий

Капча загружается...