jaki jest zsh równoważnik eksportu bash -f


24

Więc zacząłem używać zsh. Wszystko mi się podoba. Wygląda to bardzo fajnie i płynnie, a fakt, że bieżący katalog roboczy i wiersz poleceń znajdują się w różnych wierszach, jest przyjemny, ale jednocześnie zauważam, że zshmoże to być nieco wolniejsze niż bash, szczególnie podczas drukowania tekstu na ekran.

Najbardziej podobało mi się to, że zshbył „wstecznie kompatybilny” ze wszystkimi funkcjami, które zdefiniowałem w moim .bashrc.

Jeden problem. Wszystkie funkcje działają idealnie, ale nie mogę zrozumieć, jak działa system eksportujący.

.bashrcWyeksportowałem niektóre z tych funkcji, aby móc z nich korzystać w innym miejscu, na przykład w skryptach i programach zewnętrznych export -f.

W Zsh nie mówi się nawet o eksportowaniu. Czy to automatyczne ładowanie? Czy te dwie rzeczy są takie same? Trudno mi to rozgryźć.


2
To bardzo stare pytanie, ale chcę powiedzieć, że „bieżący katalog roboczy i rzeczywista linia poleceń znajdują się w różnych wierszach” nie ma nic wspólnego z zsh. To zależy od konfiguracji monitu, to wszystko.
4ae1e1

Odpowiedzi:


11

Zmienne środowiskowe zawierające funkcje to hash. Zsh nie ma nic podobnego. Możesz zrobić coś podobnego za pomocą kilku linii kodu. Zmienne środowiskowe zawierają ciągi; starsze wersje bash, zanim Shellshock został wykryty, zapisywały kod funkcji w zmiennej, której nazwa to nazwa funkcji, a po której wartości () {następuje kod funkcji, po której następuje }. Możesz użyć następującego kodu, aby zaimportować zmienne z tym kodowaniem i spróbować uruchomić je z ustawieniami podobnymi do bash. Zauważ, że zsh nie może emulować wszystkich funkcji bash, wszystko co możesz zrobić, to podejść nieco bliżej (np. Aby $foopodzielić wartość i rozwinąć symbole wieloznaczne oraz ustawić tablice na 0).

bash_function_preamble='
    emulate -LR ksh
'
for name in ${(k)parameters}; do
  [[ "-$parameters[name]-" = *-export-* ]] || continue
  [[ ${(P)name} = '() {'*'}' ]] || continue
  ((! $+builtins[$name])) || continue
  functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done

(Jak zauważył Stéphane Chazelas , oryginalny odkrywca Shellshock, wcześniejsza wersja tej odpowiedzi mogłaby w tym momencie wykonać dowolny kod, gdyby definicja funkcji była zniekształcona. Ta wersja nie, ale oczywiście po wykonaniu dowolnego polecenia, może to być funkcja importowana ze środowiska).

Wersje bash po wydaniu powłoki kodują funkcje w środowisku przy użyciu niepoprawnych nazw zmiennych (np BASH_FUNC_myfunc%%.). To sprawia, że ​​trudniej jest je niezawodnie parsować, ponieważ zsh nie udostępnia interfejsu do wyodrębnienia takich zmiennych ze środowiska.

Nie polecam tego robić. Poleganie na funkcjach eksportowanych w skryptach jest złym pomysłem: stwarza niewidoczną zależność w twoim skrypcie. Jeśli kiedykolwiek uruchomisz skrypt w środowisku, które nie ma twojej funkcji (na innym komputerze, w zadaniu cron, po zmianie plików inicjujących powłokę,…), twój skrypt nie będzie już działał. Zamiast tego przechowuj wszystkie funkcje w jednym lub kilku osobnych plikach (coś w rodzaju ~/lib/shell/foo.sh) i uruchom skrypty, importując funkcje, których używa ( . ~/lib/shell/foo.sh). W ten sposób, jeśli zmodyfikujesz foo.sh, możesz łatwo wyszukać, które skrypty na nim polegają. Jeśli skopiujesz skrypt, możesz łatwo dowiedzieć się, jakie pliki pomocnicze on potrzebuje.

Zsh (i ksh przed nim) czyni to wygodniejszym, zapewniając sposób automatycznego ładowania funkcji w skryptach, w których są one używane. Ograniczeniem jest to, że możesz umieścić tylko jedną funkcję na plik. Zadeklaruj funkcję jako automatycznie ładowaną i umieść definicję funkcji w pliku, którego nazwa jest nazwą funkcji. Umieść ten plik w katalogu wymienionym w $fpath(który możesz skonfigurować za pomocą FPATHzmiennej środowiskowej). W skrypcie deklaruj funkcje ładowane automatycznie autoload -U foo.

Ponadto zsh może kompilować skrypty, aby zaoszczędzić czas analizy. Wywołanie w zcompilecelu skompilowania skryptu. Spowoduje to utworzenie pliku z .zwcrozszerzeniem. Jeśli ten plik jest obecny autoload, załaduje skompilowany plik zamiast kodu źródłowego. Za pomocą tej zrecompilefunkcji można (ponownie) skompilować wszystkie definicje funkcji w katalogu.


1
Zabawne, że kod ma tę samą lukę w zabezpieczeniach powłoki bash(nie sprawdza, czy zawartość zmiennej jest tylko definicją funkcji i przetwarza dowolną nazwę zmiennej, taką jak HTTP_HOSTlub LC_X). W przeciwnym razie dobra odpowiedź.
Stéphane Chazelas

@ StéphaneChazelas Jeśli zamierzasz uruchamiać polecenia z funkcjami importowanymi ze środowiska, prawie się zgubiłeś. Ale zaktualizowałem kod importu, aby nie wykonywał dowolnego kodu. Nie jest to jednak bardzo przydatne, ponieważ bash post-shellshock nie koduje eksportowanych funkcji w ten sam sposób.
Gilles „SO- przestań być zły”

Naprawiłeś już odpowiednik CVE-2014-6271, ale nadal prawdopodobnie jesteś narażony na wiele luk w zabezpieczeniach typu CVE-2014-6277 / 6278 ... ponieważ nadal wystawiasz parser zsh na kodowanie w dowolnej zmiennej w tym niektóre, które potencjalnie są pod kontrolą atakujących w niektórych kontekstach (ponieważ kod zsh -c 'functions[f]=$VAR' jest analizowany, nawet jeśli ffunkcja nigdy nie jest wywoływana). Rozwiązaniem jest uwzględnienie tylko zmiennych, których nazwa jest zgodna z zarezerwowanym szablonem takim jak te $BASH_FUNC_x%%, ale, jak mówisz, zshnie ma interfejsu API do ich wyświetlania lub wyszukiwania. Musisz perlna przykład zadzwonić .
Stéphane Chazelas,

7

Jeśli umieścisz deklarację funkcji w .zshenv , twoja funkcja będzie możliwa do użycia ze skryptu bez żadnego wysiłku.


Dlaczego przegłosowałeś moją odpowiedź? Proszę wytłumacz.
rools

Wciąż czekam na odpowiedź i nadal działa!
rools

Właśnie odkryłem tę odpowiedź i jest to idealne rozwiązanie.
AFH

Nie głosowałem za tym. I TBH OP poprosił o eksportowanie rzeczy z .bashrc, co jest dość złym pomysłem, lepiej umieścić to w skrypcie, aby nie skończyć z wielkim środowiskiem. Ale twoje rozwiązanie jest tylko wariantem tego samego złego pomysłu, włóż wszystkie swoje skrypty .zshenvi spowalnia każde wywołanie zsh przez analizowanie dużej ilości kodu, który nigdy nie jest używany. Co więcej, nie jest to to samo co eksport funkcji, podobnie jak eksportowana zmienna, eksportowana funkcja jest dostępna tylko dla procesów potomnych. Podczas gdy rzeczy, które wkładasz .zshenvsą dostępne dla każdego zsh.
Metamorphic

Wreszcie, jeśli polegasz na osobistym kodzie, który umieścisz w swoim .zshenv, wtedy wszystkie twoje skrypty będą całkowicie nieprzenośne. Zwykle skrypty mogą zależeć od siebie, co jest w porządku, rozpowszechniasz je razem. Ale jeśli zależą one od posiadania specjalnych funkcji .zshenv, nikt nie będzie chciał ich używać, lub trzeba będzie je wywołać specjalnym ZDOTDIR, uniemożliwiając wykonanie własnego .zshenv. To byłby ból.
Metamorphic
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.