Interesuje mnie ustawienie zmiennych środowiskowych jednej instancji powłoki od drugiej. Postanowiłem więc przeprowadzić badania. Po odczytaniu numeru z pytaniami o to postanowiłem przetestować go.
Odrodziłem dwie pociski A i B (PID 420), obie działające zsh
. Z powłoki AI uruchomiono następujące.
sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach
Po uruchomieniu powłoki B env
widzę, że zmienna FOO jest rzeczywiście ustawiona na wartość bar. To sprawia, że myślę, że FOO został pomyślnie zainicjowany w środowisku powłoki B. Jednak jeśli spróbuję wydrukować FOO, otrzymam pustą linię, co oznacza, że nie jest ustawiony. Dla mnie wydaje się, że istnieje tu sprzeczność.
Zostało to przetestowane zarówno na moim systemie Arch GNU / Linux, jak i na maszynie Wirtualnej Ubuntu. Przetestowałem to również bash
tam, gdzie zmienna nawet nie pojawiła się w env. Jest to dla mnie rozczarowujące, ma sens, jeśli powłoka buforuje kopię swojego środowiska w czasie odrodzenia i używa tylko tego (co zasugerowano w jednym z powiązanych pytań). To wciąż nie odpowiada, dlaczego zsh
można zobaczyć zmienną.
Dlaczego wyjście jest echo $FOO
puste?
EDYTOWAĆ
Po wprowadzeniu uwag w komentarzach postanowiłem przeprowadzić nieco więcej testów. Wyniki można zobaczyć w poniższych tabelach. W pierwszej kolumnie znajduje się powłoka, do której FOO
wstrzyknięto zmienną. Pierwszy wiersz zawiera polecenie, którego wynik można zobaczyć pod nim. Zmienna FOO
był wstrzykiwany przy użyciu: sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'
. Polecenia specyficzne dla zsh: zsh -c '...'
zostały również przetestowane przy użyciu bash. Wyniki były identyczne, ich wyniki pominięto ze względu na zwięzłość.
Arch GNU / Linux, zsh 5.3.1, bash 4.4.12 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Ubuntu 16.04.2 LTS, zsh 5.1.1, bash 4.3.48 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Powyższe wydaje się sugerować, że wyniki są niezależne od dystrybucji. Nie mówi mi to nic więcej zsh
i bash
inaczej traktuję ustawianie zmiennych. Co więcej, export FOO
ma bardzo różne zachowanie w tym kontekście, w zależności od powłoki. Mam nadzieję, że testy te wyjaśnią komuś coś innego.
zsh -c 'echo $FOO'
zamiast tego użyjesz (użyj pojedynczych cudzysłowów!)? Widzisz to?env
) widzą zmodyfikowane środowisko.zsh
GDB nie powoduje, że jest ona widoczna jako zmienna powłoki, ale powoduje, że jest ona przekazywana do procesów potomnych (jako zaobserwowano), podczas gdy ustawienie jednegobash
powoduje, że jest on widoczny jako zmienna powłoki, ale nie powoduje, że jest on przekazywany do procesów potomnych! Wygląda na to, że zsh i bash używają różnych strategii zarządzania zmiennymi, z śledzeniem zmiennych nieśrodowiskowych za pomocą zsh i przechowywaniem wszystkiego w swoim środowisku, które odkaża podczas uruchamiania potomka (niebędącego podpowłoką).export FOO
wbash
?Odpowiedzi:
Większość powłok nie używa interfejsu API
getenv()
/setenv()
/putenv()
.Po uruchomieniu tworzą zmienne powłoki dla każdej zmiennej środowiskowej. Będą one przechowywane w strukturach wewnętrznych, które muszą przenosić inne informacje, takie jak to, czy zmienna jest eksportowana, tylko do odczytu ... Nie mogą do tego używać bibliotek libc
environ
.Podobnie, iz tego powodu, że nie będzie używać
execlp()
,execvp()
aby wykonywać polecenia, ale nazywająexecve()
wywołanie systemowe bezpośrednio, obliczaniaenvp[]
macierzy w oparciu o listę swoich eksportowanych zmiennych.W twoim przypadku
gdb
musisz dodać wpis do wewnętrznej tabeli zmiennych tej powłoki lub ewentualnie wywołać odpowiednią funkcję, która sprawi, że zinterpretujeexport VAR=value
kod, aby zaktualizować tę tabelę samodzielnie.Dlaczego widzisz różnicę pomiędzy
bash
izsh
podczas rozmowysetenv()
wgdb
Podejrzewam, że to dlatego, że dzwoniszsetenv()
przed inicjalizuje powłoki, na przykład przy wejściumain()
.Zauważysz
bash
, żemain()
is jestint main(int argc, char* argv[], char* envp[])
(ibash
mapuje zmienne z tych zmiennych envenvp[]
), podczas gdyzsh
is isint main(int argc, char* argv[])
izsh
pobiera zmienne z nichenviron
.setenv()
modyfikuje,environ
ale nie może modyfikowaćenvp[]
w miejscu (tylko do odczytu w kilku systemach, a także ciągów, na które wskazują te wskaźniki).W każdym razie, po odczytaniu powłoki
environ
przy uruchomieniu, użyciesetenv()
byłoby nieskuteczne, ponieważ powłoka nie używaenviron
(lubgetenv()
) później.źródło