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 zsh
może to być nieco wolniejsze niż bash
, szczególnie podczas drukowania tekstu na ekran.
Najbardziej podobało mi się to, że zsh
był „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.
.bashrc
Wyeksportował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źć.
źródło
Odpowiedzi:
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$foo
podzielić wartość i rozwinąć symbole wieloznaczne oraz ustawić tablice na 0).(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 zmodyfikujeszfoo.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ąFPATH
zmiennej środowiskowej). W skrypcie deklaruj funkcje ładowane automatycznieautoload -U foo
.Ponadto zsh może kompilować skrypty, aby zaoszczędzić czas analizy. Wywołanie w
zcompile
celu skompilowania skryptu. Spowoduje to utworzenie pliku z.zwc
rozszerzeniem. Jeśli ten plik jest obecnyautoload
, załaduje skompilowany plik zamiast kodu źródłowego. Za pomocą tejzrecompile
funkcji można (ponownie) skompilować wszystkie definicje funkcji w katalogu.źródło
bash
(nie sprawdza, czy zawartość zmiennej jest tylko definicją funkcji i przetwarza dowolną nazwę zmiennej, taką jakHTTP_HOST
lubLC_X
). W przeciwnym razie dobra odpowiedź.zsh -c 'functions[f]=$VAR'
jest analizowany, nawet jeślif
funkcja 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,zsh
nie ma interfejsu API do ich wyświetlania lub wyszukiwania. Musiszperl
na przykład zadzwonić .Jeśli umieścisz deklarację funkcji w .zshenv , twoja funkcja będzie możliwa do użycia ze skryptu bez żadnego wysiłku.
źródło
.zshenv
i 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.zshenv
są dostępne dla każdego zsh..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ć specjalnymZDOTDIR
, uniemożliwiając wykonanie własnego.zshenv
. To byłby ból.