Trudno mi zdefiniować i uruchomić własne funkcje powłoki w Zsh. Postępowałem zgodnie z instrukcjami w oficjalnej dokumentacji i najpierw spróbowałem z prostym przykładem, ale nie udało mi się go uruchomić.
Mam folder:
~/.my_zsh_functions
W tym folderze mam plik o nazwie functions_1
z rwx
uprawnieniami użytkownika. W tym pliku zdefiniowałem następującą funkcję powłoki:
my_function () {
echo "Hello world";
}
Zdefiniowałem, FPATH
aby dołączyć ścieżkę do folderu ~/.my_zsh_functions
:
export FPATH=~/.my_zsh_functions:$FPATH
Mogę potwierdzić, że folder .my_zsh_functions
znajduje się w ścieżce funkcji za pomocą echo $FPATH
lubecho $fpath
Jeśli jednak spróbuję wykonać następujące czynności z powłoki:
> autoload my_function
> my_function
Dostaję:
zsh: moja_test_funkcja: nie znaleziono pliku definicji funkcji
Czy jest coś jeszcze, co muszę zrobić, aby móc zadzwonić my_function
?
Aktualizacja:
Dotychczasowe odpowiedzi sugerują pozyskiwanie pliku za pomocą funkcji zsh. To ma sens, ale jestem trochę zdezorientowany. Czy Zsh nie powinien wiedzieć, gdzie są te pliki FPATH
? Jaki jest zatem cel autoload
tego?
źródło
Odpowiedzi:
W zsh ścieżka wyszukiwania funkcji ($ fpath) definiuje zestaw katalogów, które zawierają pliki, które można oznaczyć do automatycznego załadowania, gdy funkcja, którą zawierają, jest potrzebna po raz pierwszy.
Zsh ma dwa tryby automatycznego ładowania plików: rodzimy sposób Zsha i inny tryb podobny do automatycznego ładowania ksh. Ten ostatni jest aktywny, jeśli ustawiona jest opcja KSH_AUTOLOAD. Tryb macierzysty Zsh jest domyślny i nie będę tutaj omawiał innych sposobów (zobacz „man zshmisc” i „man zshoptions”, aby uzyskać szczegółowe informacje na temat automatycznego ładowania w stylu ksh).
W porządku. Załóżmy, że masz katalog `~ / .zfunc 'i chcesz, aby był on częścią ścieżki wyszukiwania funkcji, wykonaj następujące czynności:
To dodaje twój prywatny katalog na początku ścieżki wyszukiwania. Jest to ważne, jeśli chcesz zastąpić funkcje z instalacji zsh własną (np. Jeśli chcesz użyć zaktualizowanej funkcji uzupełniania, takiej jak `_git 'z repozytorium CVS zsh ze starszą zainstalowaną wersją powłoki).
Warto również zauważyć, że katalogi z `$ fpath 'nie są przeszukiwane rekurencyjnie. Jeśli chcesz, aby twój prywatny katalog był przeszukiwany rekurencyjnie, musisz sam o to zadbać, w ten sposób (poniższy fragment wymaga ustawienia opcji `EXTENDED_GLOB '):
Może to wyglądać tajemniczo dla niewprawnego oka, ale tak naprawdę dodaje wszystkie katalogi poniżej `~ / .zfunc 'do` $ fpath', ignorując katalogi o nazwie „CVS” (co jest przydatne, jeśli planujesz wykupić całość drzewo funkcji z CVS zsh do twojej prywatnej ścieżki wyszukiwania).
Załóżmy, że masz plik `~ / .zfunc / hello ', który zawiera następujący wiersz:
Wszystko, co musisz teraz zrobić, to zaznaczyć funkcję, która zostanie automatycznie załadowana po pierwszym odwołaniu:
„O co chodzi -Uz?”, Pytasz? Cóż, to tylko zestaw opcji, które spowodują, że `autoload 'zrobi właściwą rzecz, bez względu na to, jakie opcje są ustawione inaczej. `U 'wyłącza rozszerzenie aliasu podczas ładowania funkcji, a` z' wymusza automatyczne ładowanie w stylu zsh, nawet jeśli `KSH_AUTOLOAD 'jest ustawiony z jakiegokolwiek powodu.
Po zakończeniu tej czynności możesz użyć nowej funkcji hello:
Słowo o pozyskiwaniu tych plików: to po prostu źle . Jeśli źródłowy plik „~ / .zfunc / hello”, po prostu wydrukuje „Hello world”. pewnego razu. Nic więcej. Żadna funkcja nie zostanie zdefiniowana. Poza tym pomysł polega na ładowaniu kodu funkcji tylko wtedy, gdy jest to wymagane . Po wywołaniu `autoload 'definicja funkcji nie jest czytana. Funkcja jest właśnie oznaczona do automatycznego ładowania później w razie potrzeby.
I wreszcie uwaga na temat $ FPATH i $ fpath: Zsh zachowuje je jako parametry powiązane. Parametr pisany małymi literami to tablica. Wersja z dużymi literami jest skalarnym ciągiem znaków, który zawiera wpisy z połączonej tablicy połączone dwukropkami pomiędzy wpisami. Odbywa się to, ponieważ obsługa listy skalarów jest znacznie bardziej naturalna przy użyciu tablic, przy jednoczesnym zachowaniu kompatybilności wstecznej dla kodu korzystającego z parametru skalarnego. Jeśli wybierzesz opcję $ FPATH (skalarną), musisz zachować ostrożność:
będzie działać, podczas gdy następujące nie będą:
Powodem jest to, że interpretacja tyldy nie jest wykonywana w podwójnych cudzysłowach. Jest to prawdopodobnie źródło twoich problemów. Jeśli
echo $FPATH
drukuje tyldę, a nie rozwiniętą ścieżkę, to nie będzie działać. Dla bezpieczeństwa użyłbym $ HOME zamiast tyldy takiej jak ta:To powiedziawszy, wolałbym raczej użyć parametru tablicy, jak na początku tego objaśnienia.
Nie powinieneś również eksportować parametru $ FPATH. Jest potrzebny tylko w bieżącym procesie powłoki, a nie przez żadne z jego potomków.
Aktualizacja
Odnośnie zawartości plików w `$ fpath ':
W przypadku automatycznego ładowania w stylu zsh zawartość pliku stanowi treść zdefiniowanej przez niego funkcji. Zatem plik o nazwie „cześć” zawierający wiersz
echo "Hello world."
całkowicie definiuje funkcję o nazwie „cześć”. Możeszhello () { ... }
ominąć kod, ale byłoby to zbyteczne.Twierdzenie, że jeden plik może zawierać tylko jedną funkcję, nie jest jednak całkowicie poprawne.
Zwłaszcza jeśli spojrzysz na niektóre funkcje z systemu uzupełniania opartego na funkcjach (compsys), szybko zdasz sobie sprawę, że jest to nieporozumienie. Możesz dowolnie definiować dodatkowe funkcje w pliku funkcji. Możesz także wykonać dowolną inicjalizację, która może być konieczna przy pierwszym wywołaniu funkcji. Jednak gdy to zrobisz, zawsze zdefiniujesz funkcję o nazwie takiej jak plik w pliku i wywołasz tę funkcję na końcu pliku, aby była uruchamiana przy pierwszym wywołaniu funkcji.
Jeśli - z podfunkcjami - nie zdefiniowałeś funkcji o nazwie takiej jak plik w pliku, skończyłbyś z tą funkcją zawierającą definicje funkcji (mianowicie definicje podfunkcji w pliku). Skutecznie definiowałbyś wszystkie swoje podfunkcje przy każdym wywołaniu funkcji o nazwie takiej jak plik. Zwykle nie jest to pożądane, więc ponownie zdefiniujesz funkcję, która nazywa się jak plik w pliku.
Dołączę krótki szkielet, który da ci wyobrażenie o tym, jak to działa:
Gdybyś uruchomił ten głupi przykład, pierwszy przebieg wyglądałby tak:
Kolejne połączenia będą wyglądać następująco:
Mam nadzieję, że to wszystko wyjaśni.
(Jednym z bardziej złożonych przykładów, w których wykorzystuje się wszystkie te sztuczki, jest wspomniana już funkcja ` _tmux 'z systemu uzupełniania opartego na funkcji zsh.)
źródło
my_function () { }
w swoimHello world
przykładzie. Jeśli składnia nie jest potrzebna, kiedy warto jej użyć?Nazwa pliku w katalogu nazwanym przez
fpath
element musi być zgodna z nazwą zdefiniowanej funkcji autoloadable.Twoja funkcja ma nazwę
my_function
i~/.my_zsh_functions
jest zamierzonym katalogiem w twoimfpath
, więc definicjamy_function
powinna znajdować się w pliku~/.my_zsh_functions/my_function
.Liczba mnoga w proponowanej nazwie pliku (
functions_1
) wskazuje, że planujesz umieścić wiele funkcji w pliku. To niefpath
działa i automatyczne ładowanie działa. Powinieneś mieć jedną definicję funkcji na plik.źródło
podaj
source ~/.my_zsh_functions/functions1
terminal i oceńmy_function
, teraz będziesz mógł wywołać funkcjęźródło
FPATH
iautoload
wtedy? Dlaczego muszę również źródło pliku? Zobacz moje zaktualizowane pytanie.Możesz „załadować” plik ze wszystkimi swoimi funkcjami do $ ZDOTDIR / .zshrc w następujący sposób:
Lub można użyć kropki „.” zamiast „źródła”.
źródło
FPATH
iautoload
wtedy? Dlaczego muszę również źródło pliku? Zobacz moje zaktualizowane pytanie.Sourcing zdecydowanie nie jest właściwym podejściem, ponieważ wydaje się, że chcesz mieć leniwe funkcje inicjowane. Po to
autoload
jest. Oto, w jaki sposób osiągasz to, czego szukasz.W twojej
~/.my_zsh_functions
, mówisz, że chcesz umieścić funkcję o nazwiemy_function
że echo „Hello World”. Ale zawijasz je w wywołanie funkcji, co nie działa w ten sposób. Zamiast tego musisz utworzyć plik o nazwie~/.my_zsh_functions/my_function
. W nim po prostu umieśćecho "Hello world"
, a nie w opakowaniu funkcji. Możesz również zrobić coś takiego, jeśli naprawdę wolisz mieć opakowanie.Następnie w swoim
.zshrc
pliku dodaj:Po załadowaniu nowej powłoki ZSH wpisz
which my_function
. Powinieneś to zobaczyć:ZSH właśnie usunął dla ciebie moją funkcję
autoload -X
. Teraz biegnij,my_function
ale po prostu piszmy_function
. Powinieneś zobaczyćHello world
wydruk, a teraz po uruchomieniuwhich my_function
powinieneś zobaczyć wypełnioną funkcję w następujący sposób:Teraz prawdziwa magia pojawia się po skonfigurowaniu całego
~/.my_zsh_functions
folderu do pracyautoload
. Jeśli chcesz, aby każdy plik, który upuściłeś w tym folderze, działał w ten sposób, zmień to, co umieściłeś w swoim folderze.zshrc
na coś takiego:źródło