Sprowadza się to do pytania, jak działa ewaluacja. Oba przykłady działają w ten sam sposób, problem występuje z powodu tego, jak powłoka (bash, tutaj) rozwija zmienne.
Kiedy napiszesz to polecenie:
HOME="foo" echo $HOME
$HOME
Rozpręża przed uruchomieniem polecenia . Dlatego jest on rozwijany do pierwotnej wartości, a nie nowej, dla której ustawiono ją dla polecenia. HOME
Zmienna rzeczywiście została zmieniona w środowisku, że echo
komenda jest uruchomiony w jednak jesteś drukowanie $HOME
od rodzica.
Aby to zilustrować, rozważ to:
$ HOME="foo" bash -c 'echo $HOME'
foo
$ echo $HOME
/home/terdon
Jak widać powyżej, pierwsze polecenie drukuje tymczasowo zmienioną wartość, HOME
a drugie drukuje oryginał, pokazując, że zmienna została zmieniona tylko tymczasowo. Ponieważ bash -c ...
polecenie jest ujęte w pojedyncze cudzysłowy ( ' '
) zamiast podwójnych ( " "
), zmienna nie jest rozwijana i jest przekazywana w stanie niezmienionym do nowego procesu bash. Ten nowy proces następnie go rozwija i drukuje nową wartość, dla której został ustawiony. Możesz to zobaczyć, jeśli użyjesz set -x
:
$ set -x
$ HOME="hello" echo "$HOME"
+ HOME=hello
+ echo hello
hello
Jak widać powyżej, zmienna $HOME
nigdy nie jest przekazywana do echo
. Widzi tylko swoją rozszerzoną wartość. Porównać z:
$ HOME="hello" bash -c 'echo $HOME'
+ HOME=hello
+ bash -c 'echo $HOME'
hello
Tutaj, ze względu na pojedyncze cudzysłowy, zmienna, a nie jej wartość, są przekazywane do nowego procesu.
local
.eval
unikać tego rozwiązania?Istnieją dwa zakresy: zmienne środowiskowe i zmienne lokalne. Zmienne środowiskowe są poprawne dla każdego procesu (patrz
setenv
,getenv
), podczas gdy zmienne lokalne są aktywne tylko w tej sesji powłoki. (To nie jest oczywiste rozróżnienie ...)Implikowane
env
(jak w twoim przykładzie) modyfikuje środowisko, podczas gdyecho ...
używa lokalnych - więcenv
nie ma żadnego efektu.Aby zmodyfikować zmienne lokalne, użyj, powiedzmy,
Tutaj nawiasy określają zakres tego zadania.
źródło