Do czego służy export
?
Jaka jest różnica pomiędzy:
export name=value
i
name=value
Do czego służy export
?
Jaka jest różnica pomiędzy:
export name=value
i
name=value
Odpowiedzi:
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 export
i 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ł.
name=value command
ma sprawić, że zmienna dostępna w sub-process command
.
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
.
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.
dash
ma z tym wspólnego. Oryginalny plakat pytał konkretnie o bash
.
bash
ale dotyczy w równym stopniu każdego wariantu bourne-shell. Bycie zbyt konkretnym i udzielanie odpowiedzi, które dotyczą tylko, bash
jest wielkim złem.
bash
jest jQuery powłoki.
export makes the variable available to subshells, and that is correct
Jest to bardzo mylące użycie terminologii. Podkładki nie muszą export
dziedziczyć zmiennych. Podprocesy tak.
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 bash
pojawiające się w skrypcie).
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ą exec
poleceniem, więc nie ma już nic do wykonania tego polecenia.
&
) tworzy również podpowłokę.
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 $var
nie drukuje nic, jeśli zostanie wykonane w drugiej linii. Ale jedna podszewka var=asdf bash -c 'echo $var'; echo $var
daje asdf\nasdf
.
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, export
oznacza 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
B
Podproces 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.
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
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 export
istnieje.
export
to 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:
export
sł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.Odpowiedź Zaakceptowany Oznacza to, ale chciałbym, aby wyraźne połączenie poleceń wbudowanych powłoki:
Jak już wspomniano, export
udostę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
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:
bash-hackers.org/wiki/doku.php/scripting/processtree
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 export
polecenia 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).
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
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.
export name=value
nie jest przenośny. W zależności od tego, czego dokładnie chcesz, wypróbujname=value; export name
przenośne rozwiązanie.