Jaké obory mohou mít proměnné prostředí?

Právě jsem narazil na problém, který mi ukazuje, že nejsem jasný v rozsahu proměnných prostředí.

Snažil jsem se použijte bundle install, což je příkaz Ruby, který ke své práci používá hodnotu $GEM_HOME. Nastavil jsem $GEM_HOME, ale příkaz tuto hodnotu ignoroval, dokud jsem nepoužil export, jako v export GEM_HOME=/some/path.

Četl jsem, že to dělá proměnnou nějak „globální“ (také známou jako proměnná prostředí ), ale já to ne pochopit, co to znamená. Vím o globálech v programování, ale ne napříč odlišnými programy.

Také vzhledem k tomu, že moje nastavení takových proměnných platí pouze pro aktuální relaci shellu, jak bych je nastavil, řekněme, na daemonizovaný proces?

Jaké rozsahy mohou mít proměnné prostředí?

Odpověď

Procesy jsou organizovány jako strom: každý proces má jedinečného rodiče, kromě init který PID je vždy 1 a nemá žádného rodiče.

Vytvoření nového procesu probíhá obecně prostřednictvím dvojice fork / execv systémová volání, kde prostředí podřízeného procesu je kopie nadřazeného procesu.

Chcete-li do prostředí vložit proměnnou z prostředí, musíte ji export proměnit, aby byla rekurzivně viditelná pro všechny děti. Mějte však na paměti, že pokud dítě změní hodnotu proměnné, změněná hodnota je viditelná pouze pro ni a pro všechny procesy vytvořené po této změně (jako kopie , jako dříve řekl).

Vezměte v úvahu také to, že podřízený proces může změnit své prostředí, například jej může resetovat na výchozí hodnoty, což se pravděpodobně provádí z login pro příklad.

Komentáře

  • Ah! Dobře, nechme ‚ s zjistit, jestli tomu rozumím. Pokud v shellu řeknu FOO=bar, nastaví hodnotu pro aktuální proces shellu. Pokud spustím program jako (bundle install), vytvoří se podřízený proces, který ‚ nezíská přístup k FOO. Pokud bych ale řekl export FOO=bar, měl by k němu přístup dětský proces (a jeho potomci) . Jeden z nich by zase mohl volat export FOO=buzz ke změně hodnoty pro své potomky, nebo jen FOO=buzz ke změně hodnoty pouze pro sebe . Je to správné?
  • @NathanLong To ‚ to není úplně ono: ve všech moderních skořápkách je proměnná buď exportována (a tedy jakákoli změna hodnoty je odrážejí v prostředí potomků) nebo nejsou exportovány (což znamená, že proměnná není v prostředí). Zejména pokud je proměnná již v prostředí při spuštění prostředí, je exportována.
  • Byla jsem trochu zmatená větou „, pokud je dítě změnit hodnotu proměnné, změněná hodnota je viditelná pouze pro ni a pro všechny procesy vytvořené po této změně „. Bylo by správnější říci “ … viditelné pro něj a všechny jeho potomky vytvořené po této změně “ – ten druhý děti nadřazeného procesu, ani ty, které byly spuštěny po podřízeném procesu, nejsou ovlivněny.

Odpovědět

Na nejméně pod ksh a bash mohou mít proměnné tři obory, ne dva jak to v současné době říkají všechny zbývající odpovědi.

V kromě exportovaných proměnných (tj. prostředí) a rozsahů nevyexportovaných proměnných prostředí existuje také třetí užší pro místní proměnné funkcí.

Proměnné deklarované ve funkcích prostředí pomocí typeset je viditelný pouze uvnitř funkcí, z nichž jsou deklarovány, a v (pod) funkcích, které jsou odtud volány.

This ksh / bash code:

# Create a shell script named /tmp/show that displays the scoped variables values. echo "echo [$environment] [$shell] [$local]" > /tmp/show chmod +x /tmp/show # Function local variable declaration function f { typeset local=three echo "in function": . /tmp/show } # Global variable declaration export environment=one # Unexported (i.e. local) variable declaration shell=two # Call the function that creates a function local variable and # display all three variable values from inside the function f # Display the three values from outside the function echo "in shell": . /tmp/show # Display the same values from a subshell echo "in subshell": /tmp/show # Display the same values from a disconnected shell (simulated here by a clean environment start) echo "in other shell" env -i /tmp/show 

vytvoří tento výstup:

in function: [one] [two] [three] in shell: [one] [two] [] in subshell: [one] [] [] in other shell [] [] [] 

Jak vidíte, exportovaná proměnná se zobrazuje z prvních tří umístění, neexportované proměnné se nezobrazují mimo aktuální prostředí a lokální proměnná funkce nemá žádnou hodnotu mimo samotnou funkci. Poslední test neukazuje vůbec žádné hodnoty, je to proto, že exportované proměnné nejsou sdíleny mezi skořápkami, tj. Mohou být pouze zděděny a zděděnou hodnotu poté nemůže ovlivnit nadřazený shell.

Všimněte si, že toto druhé chování se zcela liší od chování systému Windows, kde můžete používat systémové proměnné, které jsou plně globální a sdílené všemi procesy.

Odpovědět

Jsou vymezeny procesem

Ostatní respondenti mi pomohli pochopit, že rozsah proměnné prostředí je o procesech a jejich potomci .

Když na příkazový řádek zadáte příkaz jako ls, ve skutečnosti jste rozdvojení procesu pro spuštění programu ls. Nový proces má jako nadřazený váš shell.

Každý proces může mít své vlastní „lokální“ proměnné, které jsou není předáno podřízeným procesům. Může také nastavit proměnné prostředí, které jsou. Pomocí export vytvoříte proměnnou prostředí. V obou v případě, že nesouvisející procesy (partneři originálu) proměnnou neuvidí; kontrolujeme pouze to, co dítě proc eseje viz.

Předpokládejme, že máte bash shell, kterému budeme říkat A. Napište bash , který vytvoří podřízený proces bash shell, který „zavoláme B. Cokoli, čemu jste volali export, v A bude stále nastaveno v B.

Nyní v B řeknete FOO=b. Stane se jedna ze dvou věcí:

  • Pokud B neobdržel (od A) proměnnou prostředí s názvem FOO, vytvoří místní proměnnou. Děti B to nedostanou (pokud B nezavolá export).
  • Pokud B udělal obdrží (od A) proměnnou prostředí nazvanou FOO, ji sama upraví a jeho následně rozdvojené děti . Děti B uvidí hodnotu, kterou B. přidělil. to však A vůbec neovlivní.

Zde je rychlá ukázka .

FOO=a # set "local" environment variable echo $FOO # "a" bash # forks a child process for the new shell echo $FOO # not set exit # return to original shell echo $FOO # still "a" export FOO # make FOO an environment variable bash # fork a new "child" shell echo $FOO # outputs "a" FOO=b # modifies environment (not local) variable bash # fork "grandchild" shell echo $FOO # outputs "b" exit # back to child shell exit # back to original shell echo $FOO # outputs "a" 

To vše vysvětluje můj původní problém: nastavil jsem GEM_HOME do svého shellu, ale když jsem volal bundle install, který vytvořil podřízený proces. Protože jsem nepoužil export, podřízený proces neobdržel shell GEM_HOME.

Un-export

Proměnnou můžete „un-exportovat“ – zabránit jejímu předání dětem – pomocí export -n FOO.

export FOO=a # Set environment variable bash # fork a shell echo $FOO # outputs "a" export -n FOO # remove environment var for children bash # fork a shell echo $FOO # Not set exit # back up a level echo $FOO # outputs "a" - still a local variable 

Komentáře

  • Když řeknete “ upraví to pro sebe a své děti “ měli byste ujasnit, že po úpravě vytvořily pouze děti uvidí upravenou hodnotu.
  • @enzotib – dobrý bod. Aktualizováno.

Odpověď

Nejlepším vysvětlením exportu je toto:

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html

Proměnná nastavená v subshellu nebo podřízeném prostředí je viditelná pouze pro subshell, ve kterém je definován. Exportovaná proměnná je ve skutečnosti vytvořena jako proměnná prostředí. Aby bylo jasno, váš bundle install spustí svůj vlastní shell, který $GEM_HOME nevidí, pokud není vytvořen environment Proměnná aka exportována.

Dokumentaci k proměnné oblasti si můžete prohlédnout zde:

http://www.tldp.org/LDP/abs/html/subshells.html

Komentáře

  • Ah, proto jsem nesprávně používal výraz “ proměnná prostředí “ pro FOO=bar; musíte použít export aby to bylo jedno. Otázka odpovídajícím způsobem opravena.
  • Podívejte se na odkaz, který jsem přidal.

Odpověď

Podle očekávání existuje hierarchie rozsahů proměnných.

Prostředí

Nejvzdálenějším oborem je prostředí. Toto je jediný obor spravováno operačním systémem, a proto je zaručeno, že bude existovat pro každý proces. Po spuštění procesu obdrží a kopie prostředí jeho rodiče, po kterém se oba osamostatní: úprava prostředí dítěte nezmění prostředí rodiče a úprava prostředí rodiče nezmění prostředí již existujícího dítěte.

Proměnné prostředí

Mušle mají svůj vlastní pojem proměnných. To je místo, kde věci začínají být trochu matoucí.

Když přiřadíte hodnotu proměnné v prostředí a tato proměnná již v prostředí existuje, získá proměnná prostředí novou hodnotu. Pokud však proměnná ještě není v prostředí, stane se proměnnou shell . Proměnné prostředí existují pouze v rámci procesu prostředí, podobně jako proměnné Ruby existují pouze v rámci skriptu Ruby. Nikdy nejsou zděděny podřízenými procesy.

Zde vstupuje do hry klíčové slovo export. Kopíruje proměnnou prostředí do prostředí procesu prostředí, což umožňuje dědění podřízených procesů.

Lokální proměnné

Lokální proměnné jsou proměnné prostředí definované v blocích kódu, které je obsahují. Místní proměnné deklarujete pomocí klíčového slova typeset (přenosné) nebo local nebo declare (Bash ). Stejně jako ostatní proměnné prostředí nejsou místní proměnné zděděny podřízenými procesy. Nelze také exportovat místní proměnné.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *