Właśnie natknąłem się na problem, który pokazuje mi, że nie mam jasności co do zakresu zmiennych powłoki.
Próbowałem użyć bundle install
, czyli komendy Ruby, która używa wartości $GEM_HOME
do wykonania swojej pracy. Ustawiłem $GEM_HOME
, ale polecenie zignorowało tę wartość, dopóki jej nie użyłem export
, jak w export GEM_HOME=/some/path
.
Czytam, że dzięki temu zmienna jest w jakiś sposób „globalna” (znana również jako zmienna środowiskowa ), ale nie rozumiem, co to oznacza. Wiem o globalizacji w programowaniu, ale nie w różnych programach.
Ponadto, biorąc pod uwagę, że moje ustawienie takich zmiennych dotyczy tylko bieżącej sesji powłoki, jak ustawiłbym je dla, powiedzmy, demonizowanego procesu?
Jakie zakresy mogą mieć zmienne powłoki?
źródło
FOO=bar
, ustawia wartość dla bieżącego procesu powłoki. Jeśli następnie uruchomię program podobny do (bundle install
), tworzy to proces potomny, do którego nie ma dostępuFOO
. Ale gdybym powiedziałexport FOO=bar
, proces potomny (i jego potomkowie) mieliby do niego dostęp. Jeden z nich mógłby z kolei wezwaćexport FOO=buzz
do zmiany wartości swoich potomków lub po prostuFOO=buzz
do zmiany wartości tylko dla siebie. Czy to w porządku?Przynajmniej poniżej
ksh
ibash
zmienne mogą mieć trzy zakresy, a nie dwa, jak wszystkie pozostałe odpowiedzi obecnie mówią.Oprócz eksportowanych zmiennych (tj. Środowiskowych) i nieeksportowanych zakresów zmiennych powłoki istnieje również trzeci węższy dla zmiennych lokalnych funkcji.
Zmienne zadeklarowane w funkcjach powłoki za pomocą
typeset
tokena są widoczne tylko wewnątrz funkcji, w których są zadeklarowane, oraz w wywoływanych stamtąd funkcjach (pod).Ten
ksh
/bash
kod:tworzy ten wynik:
Jak widać, wyeksportowana zmienna jest wyświetlana z pierwszych trzech lokalizacji, niewymportowane zmienne nie są wyświetlane poza bieżącą powłoką, a zmienna lokalna funkcji nie ma wartości poza samą funkcją. Ostatni test w ogóle nie pokazuje żadnych wartości, ponieważ wyeksportowane zmienne nie są współużytkowane między powłokami, tzn. Można je tylko odziedziczyć, a na dziedziczoną wartość nie może mieć wpływu powłoka nadrzędna.
Zauważ, że to ostatnie zachowanie jest zupełnie inne niż w systemie Windows, w którym można używać Zmiennych Systemowych, które są w pełni globalne i współużytkowane przez wszystkie procesy.
źródło
Ich zakres zależy od procesu
Inni respondenci pomogli mi zrozumieć, że zakres zmiennych powłoki dotyczy procesów i ich potomków .
Kiedy wpiszesz polecenie jak
ls
w wierszu poleceń, faktycznie uruchamiasz proces uruchamianials
programu. Nowy proces ma powłokę jako swojego rodzica.Każdy proces może mieć własne zmienne „lokalne”, które nie są przekazywane do procesów potomnych. Może również ustawiać zmienne „środowiskowe”, które są. Używanie
export
tworzy zmienną środowiskową. W obu przypadkach niepowiązane procesy (równorzędne oryginału) nie zobaczą zmiennej; kontrolujemy tylko to, co widzą procesy potomne.Załóżmy, że masz powłokę bash, którą nazwiemy A. Wpisujesz
bash
, która tworzy potomną powłokę bash procesu, którą nazwiemy B. Wszystko, co wywołałeśexport
w A, nadal będzie ustawione w B.Teraz w B mówisz
FOO=b
. Stanie się jedna z dwóch rzeczy:FOO
, utworzy zmienną lokalną. Dzieci B nie otrzymają go (chyba że dzwoni Bexport
).FOO
, będzie zmodyfikować go do siebie i swoich następnie rozdwojonych dzieci . Dzieci B zobaczą wartość przypisaną przez B. Nie wpłynie to jednak wcale na A.Oto szybkie demo.
Wszystko to wyjaśnia mój pierwotny problem: ustawiłem
GEM_HOME
w swojej powłoce, ale kiedy zadzwoniłembundle install
, stworzyłem proces potomny. Ponieważ nie użyłemexport
, proces potomny nie otrzymał powłokiGEM_HOME
.Cofnięcie eksportu
Możesz „cofnąć eksport” zmiennej - zapobiegając jej przekazywaniu do dzieci - za pomocą
export -n FOO
.źródło
Najlepsze wyjaśnienie dotyczące eksportowania, jakie mogę znaleźć, to:
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
Zmienna ustawiona w podpowłoce lub powłoce podrzędnej jest widoczna tylko dla podpowłoki, w której jest zdefiniowana. Wyeksportowana zmienna faktycznie jest zmienną środowiskową. Żeby było jasne,
bundle install
wykonuje własną powłokę, która nie widzi,$GEM_HOME
chyba że zostanieenvironment
zmieniona jako eksportowana aka.Możesz zajrzeć do dokumentacji dla zakresu zmiennego tutaj:
http://www.tldp.org/LDP/abs/html/subshells.html
źródło
FOO=bar
; musisz użyć,export
aby to zrobić. Pytanie odpowiednio poprawione.Zgodnie z oczekiwaniami istnieje hierarchia zakresów zmiennych.
Środowisko
Najbardziej zewnętrznym zakresem jest środowisko. Jest to jedyny zakres zarządzany przez system operacyjny i dlatego istnieje gwarancja, że będzie istniał dla każdego procesu. Po uruchomieniu procesu otrzymuje kopię środowiska rodzica, po czym oba stają się niezależne: modyfikowanie środowiska dziecka nie zmienia środowiska rodzica, a modyfikowanie środowiska rodzica nie zmienia środowiska już istniejącego.
Zmienne powłoki
Powłoki mają własne pojęcie zmiennych. To tutaj zaczyna się nieco mylić.
Gdy przypisujesz wartość do zmiennej w powłoce, a ta zmienna już istnieje w środowisku, zmienna środowiskowa otrzymuje nową wartość. Jednak jeśli zmienna nie znajduje się jeszcze w środowisku, staje się zmienną powłoki . Zmienne powłoki istnieją tylko w procesie powłoki, podobnie jak zmienne Ruby istnieją tylko w skrypcie Ruby. Nigdy nie są dziedziczone przez procesy potomne.
Oto, gdzie
export
słowo kluczowe wchodzi w grę. Kopiuje zmienną powłoki do środowiska procesu powłoki, umożliwiając dziedziczenie procesów potomnych.Zmienne lokalne
Zmienne lokalne to zmienne powłoki, których zakres obejmuje bloki kodu je zawierające. Deklarujesz zmienne lokalne za pomocą
typeset
słowa kluczowego (przenośny) lublocal
lubdeclare
(Bash). Podobnie jak inne zmienne powłoki, zmienne lokalne nie są dziedziczone przez procesy potomne. Nie można również eksportować zmiennych lokalnych.źródło