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


152

Если я бегу

export TEST=foo
echo $TEST

Это выводит foo.

Если я бегу

TEST=foo echo $TEST

Это не. Как я могу получить эту функциональность без использования экспорта или сценария?


Осторожнее, в этой истории есть нечто большее, чем кажется на первый взгляд. Я приглашаю вас проверить мой ответ.
Jasonleonhard

Ответы:


180

Это связано с тем, что оболочка раскрывает переменную в командной строке до того, как она фактически запускает команду, и в то время переменная не существует. Если вы используете

TEST=foo; echo $TEST

это будет работать.

exportзаставит переменную появиться в среде впоследствии выполненных команд (см help export., как это работает в bash ). Если вам нужно, чтобы переменная появлялась только в среде одной команды, используйте то, что вы пробовали, т.е.

TEST=foo your-application

1
Как насчет / usr / bin / env? это тоже не работает, знаете почему?
Benubird

5
Причина та же - оболочка раскрывается $TESTперед выполнением командной строки. После того, echoкак выполняется (также обратите внимание, что echoэто обычно переводится во встроенную команду оболочки, а не в /bin/echo), она видит набор переменных в своей среде. Однако echo $TESTне говорит echoвыводить содержимое переменной TESTиз ее окружения. Он говорит оболочке запускаться echoс аргументом, который в настоящее время находится в переменной, называемой TEST- и это две совершенно разные вещи.
Петер

@peterph Если оболочка раскрывает переменную в командной строке до того, как она действительно запускает команду, то почему она не раскрывает ее var=value sh -c 'echo "$var"'?
взломает

Как я объяснил вам здесь : это происходит потому, что переменные раскрываются внутри двойных кавычек (например, "… $var …"), но не внутри одинарных кавычек (например, '… $var …'). Поскольку echo "$var"внутри одиночных кавычек, вся строка передается в sh -cоболочку new ( ) без интерпретации внешней интерактивной оболочкой. … (Продолжение)
G-Man

(Продолжение)… Как вчера сказал Игал , есть два раунда разбора - хотя я считаю, что Игал неправильно понял ваш вопрос. Не существует двух циклов синтаксического анализа, кроме синтаксического анализа, выполняемого родительской оболочкой. Есть два этапа синтаксического анализа: один выполняется внешней интерактивной (родительской) оболочкой, а другой - sh -cдочерней оболочкой new ( ).
G-Man

39

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

В

var=value echo whatever

Вы передаете var=valueстроку в среду, которую получает эхо. Тем echoне менее, ничего не делает со своим списком окружения и, в любом случае, в большинстве оболочек echoон встроен и поэтому не выполняется .

Если бы вы написали

var=value sh -c 'echo "$var"'

Это было бы другое дело. Здесь мы проходим var=valueк shкоманде, и shслучается использовать его окружение. Оболочки преобразуют каждую из переменных, которые они получают из своей среды, в переменную оболочки, поэтому полученные varпеременные среды shбудут преобразованы в $varпеременную, и когда она развернет ее в этой echoкомандной строке, это станет echo value. Поскольку среда по умолчанию наследуется, echoона также получает var=valueв своей среде (или получит, если бы она была выполнена), но, опять же, echoне заботится об окружающей среде.

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

Портативно (Борн и POSIX):

(var=value; echo "1: $var"); echo "2: $var"

(...) выше запускает под-оболочку (новый процесс оболочки в большинстве оболочек), поэтому любая объявленная там переменная будет влиять только на эту под-оболочку, поэтому я ожидаю, что приведенный выше код выведет «1: значение» и «2:» или «2: все, что было установлено ранее».

С большинством Bourne-подобных оболочек вы можете использовать функции и встроенную «локальную» функцию:

f() {
  local var
  var=value
  echo "1: $var"
}
f
echo "2: $var"

С zsh вы можете использовать встроенные функции:

(){ local var=value; echo "1: $var"; }; echo "2: $var"

или же:

function { local var=value; echo "1: $var"; }; echo "2: $var"

С bash и zsh (но не с ash, pdksh или AT & T ksh) этот прием также работает:

var=value eval 'echo "1: $var"'; echo "2: $var"

Вариант , который работает в течение еще нескольких оболочек ( dash, mksh, yash) , но не zsh(если в sh/ kshэмуляции):

var=value command eval 'echo "1: $var"'; echo "2: $var"

(использование commandперед встроенным (здесь eval) в оболочках POSIX исключает их особенность (здесь присваивание переменных из них остается в силе после их возвращения))


Для моих целей это правильное решение. Я не хочу, чтобы переменная 'var' загрязняла окружающую среду, как в принятом ответе.
kronenpj

6

Вы делаете это правильно, но синтаксис bash легко неверно истолковать: вы можете подумать, что echo $TESTприводит echoк извлечению TESTenv var, а затем распечатывает его, а это не так. Так дано

export TEST=123

тогда

TEST=456 echo $TEST

включает в себя следующую последовательность:

  1. Оболочка анализирует всю командную строку и выполняет все подстановки переменных, поэтому командная строка становится

    TEST=456 echo 123
  2. Он создает временные переменные, установленные перед командой, поэтому сохраняет текущее значение TESTи перезаписывает его с помощью 456; командная строка сейчас

    echo 123
  3. Он выполняет оставшуюся команду, которая в этом случае печатает 123 в стандартный вывод (так что оставшаяся команда оболочки даже не использовала временное значение TEST)

  4. Восстанавливает ценность TEST

Вместо этого используйте printenv, поскольку он не требует подстановки переменных:

>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>

+1 Я нашел printenvполезным для тестирования / доказательства концепции (ведет себя как сценарий, а не как echo)
Дарин

5

Вы можете получить это с помощью:

TEST=foo && echo $TEST

6
В этом случае TEST=fooвыполняется как отдельный оператор - он не просто устанавливается в контексте echo.
codeforester
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.