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
Lecieć jak po sznurku
źródło
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ł.

Brian Agnew
źródło
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$ 
alp
źródło
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.

William Pursell
źródło
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.

Matyas Koszik
źródło
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.

Charles Merriam
źródło
12

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

John T.
źródło
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
Brian S. Wilson
źródło
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.
progalgo
źródło
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
flow2k
źródło
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:


źródło
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).

Dan Carter
źródło
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
Będzie
źródło
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.

Amjad
źródło
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.

Scott
źródło
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