Definiowanie zmiennej z eksportem lub bez


955

Do czego służy export?

Jaka jest różnica pomiędzy:

export name=value

i

name=value

4
Stycznie zauważ również, że export name=valuenie jest przenośny. W zależności od tego, czego dokładnie chcesz, wypróbuj name=value; export nameprzenośne rozwiązanie.
tripleee

Odpowiedzi:


1054

export udostępnia zmienną podprocesom.

To jest,

export name=value

oznacza, że ​​nazwa zmiennej jest dostępna dla każdego procesu uruchamianego z tego procesu powłoki. Jeśli chcesz, aby proces korzystał z tej zmiennej, użyj exporti uruchom proces z tej powłoki.

name=value

oznacza, że ​​zmienny zakres jest ograniczony do powłoki i nie jest dostępny dla żadnego innego procesu. Użyłbyś tego do (powiedzmy) zmiennych pętli, zmiennych tymczasowych itp.

Należy zauważyć, że eksportowanie zmiennej nie udostępnia jej procesom nadrzędnym. Oznacza to, że określenie i eksportowanie zmiennej w odrodzonym procesie nie powoduje, że jest ona dostępna w procesie, który ją uruchomił.


105
W szczególności eksport udostępnia zmienną procesom potomnym za pośrednictwem środowiska.
Beano

15
Dodałbym również, że jeśli eksport znajduje się w pliku, który „źródło” (np.. Filename), to eksportuje go również do środowiska pracy.
rogerdpack,

6
@rogerdpack nie możesz tego zrobić bez eksportu? cat> bla \ na = hi \ n. bla; echo $ a; wypisuje dla mnie „cześć”.
David Winiecki

2
Fajnie, że działa nawet bez eksportu. Sądzę więc, że podczas pobierania pliku, jeśli użyjesz eksportu, zostanie on odzwierciedlony w procesach potomnych, jeśli nie, wpłynie to tylko na lokalne środowisko bash ...
rogerdpack

19
Jest w tym jeden przypadek; name=value command ma sprawić, że zmienna dostępna w sub-process command.
Oliver Charlesworth,

254

Aby zilustrować, co mówią inne odpowiedzi:

$ foo="Hello, World"
$ echo $foo
Hello, World
$ bar="Goodbye"
$ export foo
$ bash
bash-3.2$ echo $foo
Hello, World
bash-3.2$ echo $bar

bash-3.2$ 

9
Jeszcze jeden przykład tegoal$ foobar="Whatever" bash
Alun,

70

Inni odpowiedzieli, że eksport udostępnia zmienną do podpowłoki, i jest to poprawne, ale tylko efekt uboczny. Kiedy eksportujesz zmienną, umieszcza ją w środowisku bieżącej powłoki (tj. Wywołania powłoki putenv(3)lub setenv(3)).
Środowisko procesu jest dziedziczone w całym exec, dzięki czemu zmienna jest widoczna w podpowłokach.

Edycja (z perspektywą 5 lat): to głupia odpowiedź. Celem „eksportu” jest sprawienie, aby zmienne „znajdowały się w środowisku później wykonywanych poleceń”, niezależnie od tego, czy są to podpowłoki, czy podprocesy. Naiwną implementacją byłoby po prostu umieszczenie zmiennej w środowisku powłoki, ale uniemożliwiłoby to implementację export -p.


6
Pamiętaj, że nie jest to do końca prawda. W bash, eksport rzeczywiście dodaje zmienną do środowiska bieżącej powłoki, ale tak nie jest dash. Wydaje mi się, że dodanie zmiennej do środowiska bieżącej powłoki jest najprostszym sposobem na zaimplementowanie semantyki export, ale takie zachowanie nie jest wymagane.
William Pursell,

7
Nie jestem pewien, co dashma z tym wspólnego. Oryginalny plakat pytał konkretnie o bash.
Rozgwiazda

14
Pytanie jest oznaczone, bashale dotyczy w równym stopniu każdego wariantu bourne-shell. Bycie zbyt konkretnym i udzielanie odpowiedzi, które dotyczą tylko, bashjest wielkim złem.
William Pursell,

12
bashjest jQuery powłoki.
Potherca

2
export makes the variable available to subshells, and that is correctJest to bardzo mylące użycie terminologii. Podkładki nie muszą exportdziedziczyć zmiennych. Podprocesy tak.
Amit Naidu

62

Powiedziano, że nie jest konieczne eksportowanie bash podczas odradzania podpowłoki, podczas gdy inni mówili dokładnie odwrotnie. Ważne jest, aby zwrócić uwagę na różnicę pomiędzy podpowłok (te, które są tworzone przez (), ``, $()lub pętle) i podprocesów (procesy, które są wywoływane przez nazwę, na przykład dosłowna bashpojawiające się w skrypcie).

  • Powłoki podrzędne będą miały dostęp do wszystkich zmiennych nadrzędnych, niezależnie od ich wyeksportowanego stanu.
  • Sub procesy będą tylko zobaczyć eksportowanych zmiennych.

Wspólne w tych dwóch konstrukcjach jest to, że żadne z nich nie może przekazać zmiennych z powrotem do powłoki nadrzędnej.

$ noexport=noexport; export export=export; (echo subshell: $noexport $export; subshell=subshell); bash -c 'echo subprocess: $noexport $export; subprocess=subprocess'; echo parent: $subshell $subprocess
subshell: noexport export
subprocess: export
parent:

Jest jeszcze jedno źródło nieporozumień: niektórzy uważają, że podprocesy „rozwidlone” to te, które nie widzą nieeksportowanych zmiennych. Zwykle po fork () następuje zaraz po exec () i dlatego wydaje się, że fork () jest rzeczą, której należy szukać, podczas gdy w rzeczywistości jest to exec (). Za pomocą polecenia można najpierw uruchamiać polecenia bez fork () exec, a procesy uruchomione tą metodą również nie będą miały dostępu do niewyportowanych zmiennych:

$ noexport=noexport; export export=export; exec bash -c 'echo execd process: $noexport $export; execd=execd'; echo parent: $execd
execd process: export

Zauważ, że tym razem nie widzimy parent:linii, ponieważ zastąpiliśmy powłokę nadrzędną execpoleceniem, więc nie ma już nic do wykonania tego polecenia.


Nigdy nie widziałem pętli, która sama w sobie stworzyła podpowłokę; OTOH działa potok (zawsze dla elementów innych niż ostatnie, czasami dla ostatnich, w zależności od powłoki, wersji i opcji). Backgrounding ( &) tworzy również podpowłokę.
dave_thompson_085

Co z tymi var=asdf bash -c 'echo $var'lub var=asdf exec bash -c 'echo $var'? Dane wyjściowe to asdf. Różnica ;jest istotna, jeśli zostanie umieszczona po definicji zmiennej. Jakie byłoby wyjaśnienie? Wygląda na to, że var(bez ;) względy odradzającego się podprocesu, ponieważ powłoka pochodzenia nie ma z tym nic wspólnego. echo $varnie drukuje nic, jeśli zostanie wykonane w drugiej linii. Ale jedna podszewka var=asdf bash -c 'echo $var'; echo $vardaje asdf\nasdf.
4xy

31

export NAME=value dla ustawień i zmiennych mających znaczenie dla podprocesu.

NAME=value dla zmiennych tymczasowych lub pętli prywatnych dla bieżącego procesu powłoki.

Bardziej szczegółowo, exportoznacza nazwę zmiennej w środowisku, która kopiuje się do podprocesów i ich podprocesów podczas tworzenia. Żadna nazwa ani wartość nie jest nigdy kopiowana z podprocesu.

  • Częstym błędem jest umieszczenie spacji wokół znaku równości:

    $ export FOO = "bar"  
    bash: export: `=': not a valid identifier
  • BPodproces widzi tylko wyeksportowaną zmienną ( ):

    $ A="Alice"; export B="Bob"; echo "echo A is \$A. B is \$B" | bash
    A is . B is Bob
  • Zmiany w podprocesie nie zmieniają głównej powłoki:

    $ export B="Bob"; echo 'B="Banana"' | bash; echo $B
    Bob
  • Zmienne oznaczone do eksportu mają wartości kopiowane podczas tworzenia podprocesu:

    $ export B="Bob"; echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash &
    [1] 3306
    $ B="Banana"; echo '(sleep 30; echo "Subprocess 2 has B=$B")' | bash 
    Subprocess 1 has B=Bob
    Subprocess 2 has B=Banana
    [1]+  Done         echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash
  • Tylko wyeksportowane zmienne stają się częścią środowiska ( man environ):

     $ ALICE="Alice"; export BOB="Bob"; env | grep "ALICE\|BOB"
     BOB=Bob

Teraz powinno być tak jasne, jak letnie słońce! Dzięki Brain Agnew, Alexp i Williamowi Prusellowi.


12

export udostępni zmienną wszystkim skorupom rozwidlonym z bieżącej powłoki.


11

Należy zauważyć, że można wyeksportować zmienną, a później zmienić wartość. Zmieniona wartość zmiennej będzie dostępna dla procesów potomnych. Po ustawieniu eksportu dla zmiennej musisz zrobić, export -n <var>aby usunąć właściwość.

$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset

Dzięki, to jest dokładnie ta informacja, której szukałem, ponieważ widziałem skrypt, który używał zmiennych środowiskowych, a następnie „ponownie eksportował” je z nową wartością i zastanawiałem się, czy jest to konieczne.
Mike Lippert

8

Jak być może już wiesz, UNIX pozwala procesom mieć zestaw zmiennych środowiskowych, które są parami klucz / wartość, przy czym zarówno klucz, jak i wartość są łańcuchami. System operacyjny jest odpowiedzialny za utrzymanie tych par osobno dla każdego procesu.

Program może uzyskać dostęp do swoich zmiennych środowiskowych za pośrednictwem tego interfejsu API systemu UNIX:

  • char *getenv(const char *name);
  • int setenv(const char *name, const char *value, int override);
  • int unsetenv(const char *name);

Procesy dziedziczą również zmienne środowiskowe po procesach nadrzędnych. System operacyjny jest odpowiedzialny za tworzenie kopii wszystkich „envarów” w momencie tworzenia procesu potomnego.

Bash , między innymi powłokami, może ustawiać zmienne środowiskowe na żądanie użytkownika. Po to exportistnieje.

exportto polecenie Bash, aby ustawić zmienną środowiskową dla Bash. Wszystkie zmienne ustawione za pomocą tego polecenia będą dziedziczone przez wszystkie procesy, które utworzy Bash.

Więcej o środowisku w Bash

Innym rodzajem zmiennej w Bash jest zmienna wewnętrzna. Ponieważ Bash to nie tylko interaktywna powłoka, to tak naprawdę interpreter skryptów, tak jak każdy inny interpreter (np. Python) jest w stanie zachować swój własny zestaw zmiennych. Należy wspomnieć, że Bash (w przeciwieństwie do Pythona) obsługuje tylko zmienne łańcuchowe.

Notacją do definiowania zmiennych Bash jest name=value. Te zmienne pozostają w Bash i nie mają nic wspólnego ze zmiennymi środowiskowymi przechowywanymi przez system operacyjny.

Więcej na temat parametrów powłoki (w tym zmiennych)

Warto również zauważyć, że zgodnie z podręcznikiem użytkownika Bash:

Środowisko dla dowolnej prostej komendy lub funkcji można tymczasowo rozszerzyć, poprzedzając je przypisaniami parametrów, jak opisano w Parametry powłoki . Te instrukcje przypisania wpływają tylko na środowisko widziane przez to polecenie.


Podsumowując:

  • exportsłuży do ustawienia zmiennej środowiskowej w systemie operacyjnym. Ta zmienna będzie dostępna dla wszystkich procesów potomnych utworzonych przez bieżący proces Bash.
  • Notacja zmiennej Bash (nazwa = wartość) służy do ustawiania zmiennych lokalnych dostępnych tylko dla bieżącego procesu bash
  • Zapis zmiennej Bash poprzedzający inną komendę tworzy zmienną środowiskową tylko dla zakresu tej komendy.

1
bash vars nie obsługują tylu typów jak Python, ale mają łańcuch, liczbę całkowitą i dwa rodzaje tablic („indeksowane” / tradycyjne i „asocjacyjne”, które są podobne do tablicy awk, skrótu perl lub dict Pythona). Inne muszle różnią się; tylko ciąg jest przenośny .
dave_thompson_085

7

Odpowiedź Zaakceptowany Oznacza to, ale chciałbym, aby wyraźne połączenie poleceń wbudowanych powłoki:

Jak już wspomniano, exportudostępni zmienną zarówno powłoce, jak i dzieciom. Jeśli nieexport jest używana, zmienna będzie dostępna tylko w powłoce i tylko wbudowane powłoki mogą uzyskać do niej dostęp.

To jest,

tango=3
env | grep tango # prints nothing, since env is a child process
set | grep tango # prints tango=3 - "type set" shows `set` is a shell builtin

3

Oto kolejny przykład:

VARTEST="value of VARTEST" 
#export VARTEST="value of VARTEST" 
sudo env | grep -i vartest 
sudo echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}" 
sudo bash -c 'echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}"'  

Tylko przy użyciu eksportu VARTEST wartość VARTEST jest dostępna w sudo bash -c '...'!

Dalsze przykłady patrz:


3

Dwóch twórców UNIX, Brian Kernighan i Rob Pike, wyjaśniają to w swojej książce „The UNIX Programming Environment”. Google dla tytułu i łatwo znajdziesz wersję pdf.

Odnoszą się one do zmiennych powłoki w sekcji 3.6 i skupiają się na użyciu exportpolecenia na końcu tej sekcji:

Jeśli chcesz, aby wartość zmiennej była dostępna w podpowłokach, należy użyć polecenia eksportu powłoki. (Możesz pomyśleć o tym, dlaczego nie można wyeksportować wartości zmiennej z podpowłoki do jej rodzica).


2

Aby pokazać różnicę między wyeksportowaną zmienną znajdującą się w środowisku (env) a nieeksportowaną zmienną nie znajdującą się w środowisku:

Jeśli to zrobię:

$ MYNAME=Fred
$ export OURNAME=Jim

wtedy w polu env pojawia się tylko $ OURNAME. Zmienna $ MYNAME nie znajduje się w env.

$ env | grep NAME
OURNAME=Jim

ale zmienna $ MYNAME istnieje w powłoce

$ echo $MYNAME
Fred

1

Domyślnie zmienne utworzone w skrypcie są dostępne tylko dla bieżącej powłoki; procesy potomne (podpowłoki) nie będą miały dostępu do wartości, które zostały ustawione lub zmodyfikowane. Zezwolenie procesom potomnym na wyświetlanie wartości wymaga użycia polecenia eksportowania.


0

Chociaż nie jest to wyraźnie wspomniane w dyskusji, NIE jest konieczne użycie eksportu podczas odradzania podpowłoki z wewnętrznej bash, ponieważ wszystkie zmienne są kopiowane do procesu potomnego.


Wyjaśnij, ponieważ to, co mówisz, wydaje się być sprzeczne z odpowiedziami na powyższe przykłady.
Mike Lippert,

Jest to właściwy sposób, jeśli nie chcesz, aby zmienne były eksportowane globalnie, ale były dostępne tylko dla podprocesu! Dziękuję Ci.
jtblin
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.