Jak ustawić zmienną środowiskową w wierszu poleceń i wyświetlać ją w poleceniach?

151

Jeśli ucieknę

export TEST=foo
echo $TEST

Wyprowadza foo.

Jeśli ucieknę

TEST=foo echo $TEST

To nie. Jak mogę uzyskać tę funkcjonalność bez użycia eksportu lub skryptu?

ashleysmithgpu
źródło
Ostrożnie, w tej historii jest więcej niż się początkowo wydaje. Zapraszam do sprawdzenia mojej odpowiedzi.
jasonleonhard

Odpowiedzi:

179

Wynika to z faktu, że powłoka rozwija zmienną w wierszu poleceń, zanim faktycznie uruchomi polecenie, i wówczas zmienna nie istnieje. Jeśli użyjesz

TEST=foo; echo $TEST

to będzie działać.

exportsprawi, że zmienna pojawi się w środowisku później wykonywanych poleceń (zobacz, jak to działa w bash, patrz help export). Jeśli potrzebujesz, aby zmienna pojawiła się tylko w środowisku jednego polecenia, użyj tego, co próbowałeś, tj .:

TEST=foo your-application
Peter
źródło
1
Co z / usr / bin / env? to też nie działa, wiesz dlaczego?
Benubird
5
Z tego samego powodu - powłoka rozwija się $TESTprzed wykonaniem wiersza poleceń. Po echouruchomieniu (zwróć też uwagę, że echozwykle tłumaczy się na wbudowane polecenie powłoki, a nie /bin/echo), widzi zmienną ustawioną w swoim środowisku. Jednak echo $TESTnie każe echowypisywać zawartości zmiennej TESTze swojego środowiska. Mówi powłoce, aby działała echoz argumentem będącym tym, co aktualnie znajduje się w zmiennej o nazwie TEST- i są to dwie bardzo różne rzeczy.
peterph
@peterph Jeśli powłoka rozszerza zmienną w wierszu poleceń, zanim faktycznie uruchomi polecenie, to dlaczego go nie rozwija var=value sh -c 'echo "$var"'?
haccks,
Jak ci tutaj wyjaśniłem : to dlatego, że zmienne są interpretowane w podwójnych cudzysłowach (np. "… $var …"), Ale nie w pojedynczych cudzysłowach (np '… $var …'.). Ponieważ echo "$var"znajduje się w pojedynczych cudzysłowach, cały ciąg znaków jest przekazywany do sh -cpowłoki new ( ) bez interpretacji przez zewnętrzną, interaktywną powłokę. … (Ciąg dalszy)
G-Man
( Ciąg dalszy )… Jak powiedział wczoraj igal , istnieją dwie rundy analizy składniowej - chociaż uważam, że igal źle odczytał twoje pytanie. Nie ma dwóch rund parsowania oprócz parsowania wykonywanego przez powłokę nadrzędną. Istnieją dwie rundy analizy - jedna wykonana przez zewnętrzną, interaktywną (macierzystą) powłokę, a druga przez nową ( sh -c) powłokę potomną.
G-Man
39

Podejrzewam, że chcesz mieć zmienne powłoki , które mają ograniczony zasięg, a nie zmienne środowiskowe. Zmienne środowiskowe to lista ciągów znaków przekazywanych do poleceń podczas ich wykonywania .

W

var=value echo whatever

Przekazujesz var=valueciąg znaków do środowiska, które odbiera echo. Jednak echonic nie robi z listą środowiska, a zresztą w większości powłok echojest wbudowany i dlatego nie jest wykonywany .

Jeśli napisałeś

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

To byłaby inna sprawa. Przechodzimy tutaj var=valuedo shpolecenia i shzdarza się, że korzystamy z jego środowiska. Powłoki konwertują każdą zmienną otrzymaną ze swojego środowiska na zmienną powłokową, więc otrzymywana varzmienna środowiskowa shzostanie przekonwertowana na $varzmienną, a kiedy rozwinie ją w tym echowierszu poleceń, stanie się echo value. Ponieważ środowisko jest domyślnie dziedziczone, echootrzyma również var=valuew swoim środowisku (lub zrobiłby, gdyby zostało wykonane), ale znowu echonie dba o środowisko.

Teraz, jeśli podejrzewam, że chcesz ograniczyć zakres zmiennych powłoki, istnieje kilka możliwych podejść.

Przenośny (Bourne i POSIX):

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

Powyższe (...) uruchamia podpowłokę (nowy proces powłoki w większości powłok), więc każda zadeklarowana tam zmienna wpłynie tylko na tę podpowłokę, więc spodziewam się, że powyższy kod wyświetli „1: wartość” oraz „2:” lub „2: cokolwiek-var-was-set-to-before”.

W większości powłok podobnych do Bourne'a możesz używać funkcji i wbudowanego „lokalnego”:

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

Zsh umożliwia korzystanie z funkcji wbudowanych:

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

lub:

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

W przypadku bash i zsh (ale nie ash, pdksh lub AT&T ksh) ta sztuczka działa również:

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

Wariant, który działa w kilku więcej skorup ( dash, mksh, yash) ale nie zsh(chyba, że w sh/ kshemulacji):

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

(użycie commandprzed specjalnym wbudowanym (tutaj eval) w powłokach POSIX usuwa ich specjalność (tutaj, przypisania zmiennych z nich obowiązują po ich powrocie))

Stéphane Chazelas
źródło
Dla moich celów jest to właściwe rozwiązanie. Nie chcę, aby zmienna „var” zanieczyszczała środowisko, tak jak ma to miejsce w przyjętej odpowiedzi.
kronenpj
6

Robisz to poprawnie, ale składnia bash jest łatwa do błędnej interpretacji: możesz pomyśleć, że echo $TESTpowoduje echoto pobranie TESTenv var, a następnie wydrukowanie go, nie robi tego. Tak podane

export TEST=123

następnie

TEST=456 echo $TEST

obejmuje następującą sekwencję:

  1. Powłoka analizuje cały wiersz poleceń i wykonuje wszystkie podstawienia zmiennych, więc wiersz poleceń staje się

    TEST=456 echo 123
  2. Tworzy zmienne temp ustawione przed poleceniem, więc zapisuje bieżącą wartość TESTi zastępuje ją wartością 456; linia komend jest teraz

    echo 123
  3. Wykonuje pozostałe polecenie, które w tym przypadku wypisuje 123 na standardowe wyjście (więc polecenie powłoki, które pozostaje, nawet nie używało wartości temp TEST)

  4. Przywraca wartość TEST

Zamiast tego użyj printenv, ponieważ nie wiąże się to z podstawieniem zmiennych:

>> 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
>>
Oliver
źródło
+1 Uważam, że jest printenvpomocny w testowaniu / weryfikacji koncepcji (zachowuje się jak skrypt, w przeciwieństwie do echo)
Daryn
5

Możesz zacząć działać, używając:

TEST=foo && echo $TEST
pradeepchhetri
źródło
6
W tym przypadku TEST=foodziała jako osobna instrukcja - nie jest ona ustawiona tylko w kontekście echo.
codeforester