У zsh шлях пошуку функції ($ fpath) визначає набір каталогів, які містять файли, які можуть бути позначені для завантаження автоматично, коли функція, яку вони містять, потрібна вперше.
Zsh має два режими автозавантаження файлів: рідний спосіб Zsh та інший режим, що нагадує автоматичне завантаження ksh. Останній активний, якщо встановлено параметр KSH_AUTOLOAD. Рідний режим Zsh є типовим, і я не буду обговорювати іншого шляху (див. "Man zshmisc" та "man zshoptions" для деталей про автоматичне завантаження у стилі ksh).
Добре. Скажіть, у вас є каталог `~ / .zfunc ', і ви хочете, щоб він був частиною шляху пошуку функції, зробіть це:
fpath=( ~/.zfunc "${fpath[@]}" )
Це додає ваш приватний каталог на передню частину шляху пошуку. Це важливо, якщо ви хочете замінити функції з установки zsh своїми власними (наприклад, коли ви хочете використовувати оновлену функцію завершення, наприклад `_git 'із сховища CVS zsh із старішою встановленою версією оболонки).
Варто також зазначити, що каталоги з $ $ fpath не шукаються рекурсивно. Якщо ви хочете, щоб ваш приватний каталог рекурсивно шукався, вам доведеться подбати про це самостійно, як це (наступний фрагмент вимагає встановити опцію `EXTENDED_GLOB '):
fpath=(
~/.zfuncs
~/.zfuncs/**/*~*/(CVS)#(/N)
"${fpath[@]}"
)
Це може виглядати недосвідченим для очей, але це дійсно просто додає всі каталоги нижче `~ / .zfunc 'до` $ fpath', ігноруючи каталоги під назвою "CVS" (що корисно, якщо ви плануєте перевірити ціле дерево функцій із CVS zsh у ваш приватний шлях пошуку).
Припустимо, ви отримали файл `~ / .zfunc / hello ', який містить такий рядок:
printf 'Hello world.\n'
Все, що вам потрібно зробити зараз, - позначити функцію, яка автоматично завантажується при першій посиланні:
autoload -Uz hello
"Про що йдеться -Uz?", Запитаєте ви? Ну, це лише набір параметрів, які змусять автозавантаження робити правильно, незалежно від того, які параметри встановлюються інакше. "U" вимикає розширення псевдоніму під час завантаження функції, а "z" примушує автоматично завантажувати стиль zsh, навіть якщо з будь-якої причини встановлено `KSH_AUTOLOAD '.
Після того, як це буде зроблено, ви можете скористатися новою функцією `привіт ':
zsh% привіт
Привіт Світ.
Слово про пошук цих файлів: Це просто неправильно . Якщо ви створили б файл ~ ~ / .zfunc / hello, він просто надрукував би "Здрастуй, світ". один раз. Більше нічого. Жодна функція не буде визначена. І крім того, ідея полягає у завантаженні коду функції лише тоді, коли це потрібно . Після виклику автозавантаження визначення функції не зчитується. Функція просто позначена для автоматичного завантаження пізніше.
І нарешті, примітка про $ FPATH та $ fpath: Zsh підтримує їх як пов'язані параметри. Нижній параметр регістру - це масив. Верхня версія верхнього регістру - це скалярний рядок, який містить записи з пов'язаного масиву, з'єднаного колонами між записами. Це робиться, тому що обробка списку скалярів набагато природніше за допомогою масивів, зберігаючи також сумісність для коду, що використовує скалярний параметр. Якщо ви вирішили використовувати $ FPATH (скалярний), вам потрібно бути обережним:
FPATH=~/.zfunc:$FPATH
буде працювати, тоді як наступне не буде:
FPATH="~/.zfunc:$FPATH"
Причина полягає в тому, що розширення тильди не виконується в подвійних лапках. Це, ймовірно, джерело ваших проблем. Якщо echo $FPATH
друкує тильду, а не розгорнутий шлях, це не спрацює. Для безпеки я б використав $ HOME замість тильди на зразок цього:
FPATH="$HOME/.zfunc:$FPATH"
Зважаючи на це, я скоріше використовую параметр масиву, як я це робив у верхній частині цього пояснення.
Ви також не повинні експортувати параметр $ FPATH. Він потрібен лише поточному процесу оболонки, а не будь-якому з його дітей.
Оновлення
Щодо вмісту файлів у `$ fpath ':
При автоматичному завантаженні в стилі zsh вміст файлу є частиною функції, яку він визначає. Таким чином, файл з назвою "привіт", що містить рядок, echo "Hello world."
повністю визначає функцію, що називається "привіт". Ви можете ввести
hello () { ... }
код, але це було б зайвим.
Однак твердження, що один файл може містити лише одну функцію, не зовсім коректне.
Особливо, якщо ви подивитеся на деякі функції з системи функціонування (compsys), ви швидко зрозумієте, що це помилкова думка. Ви можете визначати додаткові функції у файлі функцій. Ви також можете зробити будь-яку ініціалізацію, яка може знадобитися зробити при першому виклику функції. Однак, коли ви це робите, ви завжди визначатимете функцію, яка названа як файл у файлі, і викличте цю функцію в кінці файлу, тому вона запускається при першому посиланні на функцію.
Якщо - з підфункціями - ви не визначили у файлі функцію, названу як файл, ви отримаєте в ній функцію з визначенням функцій (а саме підфункцій у файлі). Ви б ефективно визначали всі свої підфункції кожного разу, коли ви викликаєте функцію, названу як файл. Зазвичай, це не те, що ви хочете, тому ви б перезначили функцію, яка називається як файл у файлі.
Я включу короткий скелет, який дасть вам уявлення про те, як це працює:
# Let's again assume that these are the contents of a file called "hello".
# You may run arbitrary code in here, that will run the first time the
# function is referenced. Commonly, that is initialisation code. For example
# the `_tmux' completion function does exactly that.
echo initialising...
# You may also define additional functions in here. Note, that these
# functions are visible in global scope, so it is paramount to take
# care when you're naming these so you do not shadow existing commands or
# redefine existing functions.
hello_helper_one () {
printf 'Hello'
}
hello_helper_two () {
printf 'world.'
}
# Now you should redefine the "hello" function (which currently contains
# all the code from the file) to something that covers its actual
# functionality. After that, the two helper functions along with the core
# function will be defined and visible in global scope.
hello () {
printf '%s %s\n' "$(hello_helper_one)" "$(hello_helper_two)"
}
# Finally run the redefined function with the same arguments as the current
# run. If this is left out, the functionality implemented by the newly
# defined "hello" function is not executed upon its first call. So:
hello "$@"
Якби ви запустили цей нерозумний приклад, перший запуск виглядав би так:
zsh% привіт
ініціалізація ...
Привіт Світ.
І послідовні дзвінки будуть виглядати приблизно так:
zsh% привіт
Привіт Світ.
Я сподіваюся, що це все прояснить.
(Одним із складніших прикладів реального світу, який використовує всі ці хитрощі, є вже згадана функція _tmux 'із системи завершення, заснованої на функціях zsh.)