Як встановити змінну середовища в командному рядку і чи відображається вона в командах?


151

Якщо я біжу

export TEST=foo
echo $TEST

Він видає foo.

Якщо я біжу

TEST=foo echo $TEST

Це не. Як я можу отримати цю функціональність без використання експорту чи сценарію?


Обережно, до цієї історії є більше, ніж спочатку здається. Я запрошую вас перевірити мою відповідь.
Jasonleonhard

Відповіді:


179

Це пояснюється тим, що оболонка розширює змінну в командному рядку, перш ніж вона фактично виконує команду, і на той момент змінної не існує. Якщо ви використовуєте

TEST=foo; echo $TEST

це спрацює.

exportзробить змінну з'являтися в середовищі згодом виконаних команд (про те, як це працює в bash див. help export). Якщо вам потрібна лише змінна для відображення в середовищі однієї команди, використовуйте те, що ви спробували, тобто:

TEST=foo your-application

1
Що про / usr / bin / env? це теж не працює, ти знаєш чому?
Benubird

5
Ця ж причина - оболонка розгортає $TESTперед виконанням командного рядка. Після echoзапуску (також зауважте, що echoзазвичай перекладається на вбудовану команду оболонки, а не на /bin/echo), вона бачить змінну, встановлену в її середовищі. Однак echo $TESTне повідомляє echoвиводити вміст змінної TESTзі свого середовища. Він повідомляє оболонці запускатись echoіз аргументом, який є тим, що зараз є у змінній, що називається TEST- і це дві дуже різні речі.
петерф

@peterph Якщо shell розширює змінну в командному рядку, перш ніж вона насправді виконує команду, то чому вона не розгортає її var=value sh -c 'echo "$var"'?
хакі

Як я вам пояснив тут : це тому, що змінні розширюються всередині подвійних лапок (наприклад, "… $var …"), а не всередині одиничних лапок (наприклад, '… $var …'). Оскільки echo "$var"є всередині одинарних лапок, вся ця рядок передається новій ( sh -c) оболонці без інтерпретації зовнішньої, інтерактивної оболонки. … (Продовження)
G-Man

(Продовжував)… Як вчора сказав Ігал , є два раунди розбору, хоча я вважаю, що ігал неправильно прочитав ваше запитання. Існує не два раунди розбору, крім розбору, який виконується батьківською оболонкою. Існує два раунди синтаксичного розбору - один зроблений зовнішньою, інтерактивною (батьківською) оболонкою, а другий - новою ( sh -c) дочірньою оболонкою.
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це не хвилює оточення.

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

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

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

Вище (...) запускає підзагін (новий процес оболонки в більшості оболонок), тому будь-яка змінна заявлена ​​там буде впливати лише на цю під оболонку, тож я очікую, що код вище виведе "1: значення" і "2:" або "2: все, що було варі-було встановлено раніше".

У більшості оболонок, подібних до Борна, ви можете використовувати функції та "локальний" вбудований:

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 (але не золом, 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 в stdout (так що команда оболонки, що залишається, навіть не використовувала значення temp 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.