Jeśli procesy dziedziczą środowisko rodzica, dlaczego potrzebujemy eksportu?

72

Przeczytałem tutaj, że celem exportpowłoki jest udostępnienie zmiennej podprocesom uruchamianym z powłoki.

Jednak przeczytałem tu i tutaj, że „Procesy dziedziczą swoje środowisko po rodzicach (proces, który je rozpoczął)”.

Jeśli tak jest, dlaczego potrzebujemy export? czego mi brakuje?

Czy zmienne powłoki nie są domyślnie częścią środowiska? Jaka jest różnica?

Amelio Vazquez-Reina
źródło

Odpowiedzi:

74

Zakładasz, że zmienne powłoki znajdują się w środowisku . To jest niepoprawne. To exportpolecenie definiuje w ogóle nazwę środowiska. A zatem:

a=1 b=2
export b

powoduje, że bieżąca powłoka wie, że $arozwija się do 1 i $b2, ale podprocesy nie będą wiedziały nic, aponieważ nie są częścią środowiska (nawet w bieżącej powłoce).

Niektóre przydatne narzędzia:

  • set: Przydatny do przeglądania parametrów bieżącej powłoki, wyeksportowanych lub nie
  • set -k: Ustawia przypisane argumenty w środowisku. Rozważaćf() { set -k; env; }; f a=1
  • set -a: Mówi powłoce, aby umieściła dowolną nazwę ustawianą w środowisku. Jak stawianie exportprzed każdym zadaniem. Przydatne dla .envplików, jak w set -a; . .env; set +a.
  • export: Mówi powłoce, aby umieściła nazwę w środowisku. Eksport i przypisanie to dwie całkowicie różne operacje.
  • env: Jako zewnętrzne polecenie, envmoże ci powiedzieć tylko o odziedziczonym środowisku, dlatego jest przydatne do sprawdzania czystości.
  • env -i: Przydatne do czyszczenia środowiska przed rozpoczęciem podprocesu.

Alternatywy dla export:

  1. name=val command # Przypisanie przed poleceniem eksportuje tę nazwę do polecenia.
  2. declare/local -x name # Eksportuje nazwę, szczególnie przydatną w funkcjach powłoki, gdy chcesz uniknąć wystawiania nazwy poza zasięgiem.
  3. set -a # Eksportuje każde następne zadanie.
kojiro
źródło
3
set -kjest taki, że można użyć cmd ENVVAR=valuezamiast ENVVAR=value cmd, który nie będzie działał w twoim przykładzie, chyba że set -kzostał uruchomiony przed wywołaniem f. Ponadto niewiele powłok obsługuje go obecnie i tylko dla kompatybilności wstecznej z powłoką Bourne'a. W powłoce Bourne'a (lub Korna) nie działałoby to dla funkcji. A ponieważ wpływa na parsowanie powłoki, musi obowiązywać w momencie, gdy powłoka odczytuje kod, który z niej korzysta.
Stéphane Chazelas,
1
Warto również wspomniećset -a
Stéphane Chazelas,
24

Istnieje różnica między zmiennymi powłoki a zmiennymi środowiskowymi. Jeśli zdefiniujesz zmienną powłoki bez exportjej wczytania, nie zostanie ona dodana do środowiska procesów, a zatem nie odziedziczona po jej elementach potomnych.

Za pomocą polecenia exportkaż powłoce dodać zmienną powłoki do środowiska. Możesz to przetestować za pomocą printenv(który po prostu wypisuje swoje środowisko stdout, ponieważ jest to proces potomny, w którym widać efekt exporting zmiennych):

#!/bin/sh

MYVAR="my cool variable"

echo "Without export:"
printenv | grep MYVAR

echo "With export:"
export MYVAR
printenv | grep MYVAR
Andreas Wiese
źródło
6

Po wyeksportowaniu zmienna jest częścią środowiska. PATHjest eksportowany do samej powłoki, a zmienne niestandardowe można eksportować w razie potrzeby. Za pomocą kodu instalacyjnego:

$ cat subshell.sh 
#!/usr/bin/env bash
declare | grep -e '^PATH=' -e '^foo='

Porównać

$ cat test.sh 
#!/usr/bin/env bash
export PATH=/bin
export foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test.sh 
PATH=/bin
foo=bar
PATH=/bin
foo=bar

Z

$ cat test2.sh 
#!/usr/bin/env bash
PATH=/bin
foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test2.sh 
PATH=/bin
foo=bar
PATH=/bin

Ponieważ foonie jest eksportowany przez powłokę i test2.shnigdy go nie eksportował, nie był częścią środowiska subshell.shw ostatnim uruchomieniu.

l0b0
źródło