Dlaczego bash nawet parsuje / uruchamia rzeczy w zmiennej środowiskowej?

9

Shellshock błąd w bash działa na zasadzie zmiennych środowiskowych. Szczerze mówiąc, byłem zaskoczony faktem, że istnieje taka funkcja, jak:

„przekazywanie definicji funkcji przez zmienne env”

Dlatego pytanie, choć może nie do końca sformułowane, ma na celu podanie przykładu lub przypadku, w którym konieczne byłoby posiadanie tej funkcji?

Premia. Czy inne powłoki Zsh, Dash itp. Również mają tę funkcję?

ludzkośćANDpeace
źródło
Wykorzystuje zmienne env do przekazywania definicji funkcji. Co masz na myśli mówiąc „Dlaczego nie tylko utrzymuje zmienne środowiskowe dostępne / dostępne?” ?
Anthon
@Anthon Dzięki za komentarz. Może powinienem być jaśniejszy i sformułować inaczej. Z jakiego powodu konieczna jest możliwość przekazywania definicji funkcji za pomocą zmiennych env?
humanityANDpeace
1
Nie jestem w 100% pewien, ale myślę, że np. GNU parallelrozpowszechnia definicje funkcji, jeśli wywołuje wiele instancji bash. Jeśli nie w ten sposób, będzie musiał zapisać je w pliku, w którym czytane jest każde wywoływane wystąpienie, a następnie trzeba poradzić sobie z problemami, na przykład kiedy można usunąć ten plik.
Anthon
2
ten wątek ma trochę historii. funkcje eksportowane są jednak szalone . jeśli chcesz, aby nowa powłoka odziedziczyła stare polecenia wykonywalne powłoki, możesz .dotpobrać ten sam plik, co stara powłoka. tak to się robi - i to ma sens - lub podajesz nową powłokę do pliku jako dane wejściowe podczas execing. po jego wczytaniu, gdy i tak plik jest buforowany przez jądro.
mikeserv
@mikeserv Czy dobrze rozumiem, że duża część szoku związana jest z tą funkcją, która i tak nie jest tak istotna?
humanityANDpeace

Odpowiedzi:

4

Kiedy skrypt wywołuje inny skrypt, zmienne skryptu nadrzędnego można wyeksportować, a następnie będą widoczne w skrypcie potomnym. Eksportowanie funkcji jest oczywistym uogólnieniem: wyeksportuj funkcję od rodzica, uczyń ją widoczną w dziecku.

Środowisko to jedyny wygodny sposób, w jaki proces może przekazywać dowolne dane swoim dzieciom. Dane muszą zostać połączone w ciągi znaków, które nie zawierają pustych bajtów, co nie jest trudnością dla funkcji powłoki. Istnieją inne potencjalne metody, takie jak bloki pamięci współużytkowanej lub pliki tymczasowe przekazywane przez deskryptory plików, ale mogą powodować problemy z programami pośrednimi, które nie wiedzą, co z nimi zrobić lub je zamkną. Programy oczekują działania w środowisku zawierającym zmienne, których nie znają lub o które nie dbają, więc nie zostaną zastąpione ani usunięte.

Wybór użycia nazwy funkcji jako nazwy zmiennej środowiskowej jest dziwny. Po pierwsze, oznacza to, że eksportowana zmienna koliduje z eksportowaną funkcją o tej samej nazwie.

Eksportowane funkcje to stara funkcja. Funkcje zostały dodane w powłoce Bourne'a w SVR2 , a funkcje eksportowane w powłoce wersji 8 wydanej w tym samym roku (1984). W tej powłoce zmienne i funkcje używały tej samej przestrzeni nazw. Nie wiem, jak działał eksport funkcji. Scheda powłoka jest oparta na wariantu Bourne, który ma funkcje, ale ich nie eksportować.

ATT ksh podobno obsługuje funkcje eksportowania, ale patrząc na źródło lub grając z nim, nie widzę, że działa, jak na ksh93u.

env -i /usr/bin/ksh -c 'f=variable; f () { echo function; }; typeset -fx f; /usr/bin/env; ksh -c f'
_=*25182*/usr/bin/env
PWD=/home/gilles
SHLVL=1
A__z="*SHLVL
ksh: f: not found

Klony domeny publicznej Ksh (pdksh, mksh), myślnik i zsh nie obsługują funkcji eksportowania.

Gilles „SO- przestań być zły”
źródło
1
Dziękuję Ci! Zatem bez funkcji eksportowania funkcja traci swoją funkcjonalność, ale istnieją pewne powłoki, takie jak dash, zsh i pdksh itp., Które nie mają tej funkcjonalności, czy dobrze to przeczytałem?
humanityANDpeace
Ale kiedy eksportuję funkcję w bash, przechodzi ona do zmiennej takiej jak BASH_FUNC_f%%=() { echo hi }. Dlaczego bash parsuje inne zmienne środowiskowe? Dlaczego miałby nawet analizować, BASH_FUNC_g%%gdy dzwonię tylko f? (Najwyraźniej przed wstrząsem zmienna środowiskowa została właśnie wywołana flub g- ale wciąż zastanawiam się, dlaczego gzostałby przeanalizowany, jeśli nigdy nie wywołałbym gswojego skryptu)
Metamorphic
@Met Musi spojrzeć na wszystkie zmienne środowiskowe, aby dowiedzieć się, które z nich są definicjami funkcji. Może zapamiętać ten fakt i uniknąć analizowania kodu funkcji do pierwszego użycia, ale byłaby to dodatkowa złożoność przy bardzo niewielkim zysku. Łatwiej jest mieć tylko jeden typ funkcji, a nie dwa („funkcja normalna” i „funkcja ze zmiennej środowiskowej, która wymaga nieco analizy”).
Gilles 'SO - przestań być zły'
Nie jasne. Sugeruję, że oczywistą rzeczą do zrobienia byłoby, gdy uruchomię coś o nazwie f, (1) sprawdź, czy funkcja powłoki jest wywoływana f, (2) sprawdź zmienną środowiskową o nazwie fi spróbuj ją przeanalizować, (3) sprawdź każdy PATHkomponent dla pliku wykonywalnego o nazwie f. Jak parsowanie każdej zmiennej środowiskowej jako kodu powłoki podczas uruchamiania powłoki może wydawać się mniej skomplikowanym projektem?
Metamorphic
@ Metamorphic Sugerujesz dodanie kolejnego kroku, który należy wykonać przy każdym poleceniu. Trzeba też dodać kolejny krok podczas definiowania lub niezdefiniowania funkcji (po unset -f foo, bash nie musi już szukać definicji funkcji foow środowisku), podczas wyświetlania funkcji (jak radzisz sobie z declare -finnymi niż odczytywanie wszystkich zmiennych środowiskowych?) i cokolwiek innego, o czym nie myślę. Twój projekt wydaje się łatwiejszy, ponieważ większość z niego pominąłeś. W przeciwieństwie do tego, robienie wszystkiego przy starcie to pojedynczy fragment kodu, a potem wszystko po prostu działa.
Gilles 'SO - przestań być zły'