Jaka jest różnica między ustawieniem, eksportem i env i kiedy powinienem ich używać?

112

Co jakiś czas wypuszczam skrypt bashowy i uderza mnie kilka sposobów ustawienia zmiennej:

key=value
env key=value
export key=value

Kiedy znajdujesz się w skrypcie lub pojedynczym poleceniu (na przykład często łączę zmienną z programem uruchamiającym Wine, aby ustawić odpowiedni prefiks Wine), wydaje się, że są one całkowicie wymienne, ale na pewno tak nie jest.

Jaka jest różnica między tymi trzema metodami i czy możesz podać mi przykład, kiedy chciałbym konkretnie użyć każdej z nich?

Zdecydowanie związane z Jaka jest różnica między `VAR = ...` a `export VAR = ...`? ale chcę wiedzieć, jak envdo tego pasuje, i kilka przykładów pokazujących zalety każdego z nich byłoby również miłe :)

Oli
źródło
5
Zauważ, że export key=valuejest to rozszerzona składnia i nie należy jej używać w przenośnych skryptach (tj #! /bin/sh.).
Simon Richter

Odpowiedzi:

110

Rozważmy konkretny przykład. grepKomenda używa zmiennej środowiskowej o nazwie GREP_OPTIONSustawić domyślne opcje.

Teraz. Biorąc pod uwagę, że plik test.txtzawiera następujące wiersze:

line one
line two

uruchomienie polecenia grep one test.txtpowróci

line one

Jeśli uruchomisz grep z -vopcją, zwróci niepasujące linie, więc wynik będzie

line two

Spróbujemy teraz ustawić opcję za pomocą zmiennej środowiskowej.

  1. Zmienne środowiskowe ustawione bez exportnie będą dziedziczone w środowisku wywoływanych poleceń.

    GREP_OPTIONS='-v'
    grep one test.txt
    

    Wynik:

    line one

    Oczywiście opcja -vnie została przekazana grep.

    Chcesz użyć tego formularza, gdy ustawiasz zmienną tylko dla powłoki, na przykład for i in * ; do, jeśli nie chcesz eksportować $i.

  2. Jednak zmienna jest przekazywana do środowiska tego konkretnego wiersza poleceń, więc możesz to zrobić

    GREP_OPTIONS='-v' grep one test.txt

    który zwróci oczekiwany

    line two

    Ten formularz służy do tymczasowej zmiany środowiska tego konkretnego wystąpienia uruchomionego programu.

  3. Wyeksportowanie zmiennej powoduje jej odziedziczenie:

    export GREP_OPTIONS='-v'
    grep one test.txt
    

    powraca teraz

    line two

    Jest to najczęstszy sposób ustawiania zmiennych w celu użycia później uruchomionych procesów w powłoce

  4. Wszystko to odbyło się w bash. exportjest wbudowanym bash; VAR=whateverjest składnią bash. envz drugiej strony jest programem samym w sobie. Po envwywołaniu zdarzają się następujące rzeczy:

    1. Polecenie envzostanie wykonane jako nowy proces
    2. env modyfikuje środowisko oraz
    3. wywołuje polecenie podane jako argument. envProces otrzymuje przez commandproces.

    Przykład:

    env GREP_OPTIONS='-v' grep one test.txt

    To polecenie uruchomi dwa nowe procesy: (i) env i (ii) grep (w rzeczywistości drugi proces zastąpi pierwszy). Z punktu widzenia grepprocesu wynik jest dokładnie taki sam jak uruchomienie

    GREP_OPTIONS='-v' grep one test.txt

    Możesz jednak użyć tego idiomu, jeśli jesteś poza bashem lub nie chcesz uruchamiać kolejnej powłoki (na przykład, gdy używasz exec()rodziny funkcji zamiast system()wywołania).

Dodatkowa uwaga dotycząca #!/usr/bin/env

Dlatego też #!/usr/bin/env interpreterużywa się tego idiomu #!/usr/bin/interpreter. envnie wymaga pełnej ścieżki do programu, ponieważ korzysta z execvp()funkcji, która przeszukuje PATHzmienną tak, jak robi to powłoka, a następnie zastępuje się uruchomieniem polecenia. Dlatego można go użyć, aby dowiedzieć się, gdzie interpreter (jak perl lub python) „siedzi” na ścieżce.

Oznacza to również, że modyfikując bieżącą ścieżkę, możesz wpływać na to, który wariant Pythona zostanie wywołany. Umożliwia to:

echo -e '#!/usr/bin/bash\n\necho I am an evil interpreter!' > python
chmod a+x ./python
export PATH=.
calibre

zamiast uruchomić Calibre, spowoduje

I am an evil interpreter!
styczeń
źródło
Dlaczego GREP_OPTIONS = '- v' grep one test.txt działa? Myślałem, że potrzebuje średnika po „-v” (ale spróbowałem i faktycznie działa.)
Joe
2
Ponieważ w przypadku średnika jest on interpretowany jako dwie osobne komendy bash; pierwszy ustawia zmienną (bez eksportowania), a drugi rozpoczyna się w środowisku, w którym zmienna nie jest eksportowana. Jednak bez średnika jest to jedno polecenie (grep), poprzedzone ustawieniem lokalnego środowiska.
stycznia
Skąd jednak pochodzą wszystkie zmienne env? Mam na myśli, że kiedy otwierasz nową powłokę, zawsze masz kilka zmiennych. Więc jakiś program musiał je exportedytować, prawda?
Pithikos
1
@Pithikos Zmienne środowiskowe są ustawiane przez „pozyskiwanie środowiska”. Domyślnie bash pobierze systemowe bashrc (lub profile.d lub bash_profile). Następnie źródło użytkownika ~ / .bashrc (i / lub ~ / .bash_profile). Każdy z tych plików może zawierać polecenia bash do pozyskiwania innych skryptów, dzięki czemu możesz mieć zmienne środowiskowe pochodzące z dowolnego miejsca.
Eric
5
Co set var=blah?
CMCDragonkai