В zsh путь поиска функции ($ fpath) определяет набор каталогов, которые содержат файлы, которые могут быть помечены для автоматической загрузки, когда функция, которую они содержат, требуется в первый раз.
Zsh имеет два режима автозагрузки файлов: собственный способ Zsh и другой режим, который напоминает автозагрузку ksh. Последний активен, если установлена опция KSH_AUTOLOAD. Нативный режим Zsh используется по умолчанию, и я не буду обсуждать здесь другие способы (см. «Man zshmisc» и «man zshoptions» для получения подробной информации о автозагрузке в стиле ksh).
Хорошо. Скажем, у вас есть каталог `~ / .zfunc ', и вы хотите, чтобы он был частью пути поиска функции, вы делаете это:
fpath=( ~/.zfunc "${fpath[@]}" )
Это добавляет ваш личный каталог в передней части пути поиска. Это важно, если вы хотите переопределить функции из установки zsh своей собственной (например, когда вы хотите использовать обновленную функцию завершения, такую как _git из репозитория zsh CVS, с более старой установленной версией оболочки).
Стоит также отметить, что каталоги из $ fpath не ищутся рекурсивно. Если вы хотите, чтобы ваш личный каталог подвергался рекурсивному поиску, вам придется позаботиться об этом самостоятельно, как показано ниже (в следующем фрагменте кода должна быть задана опция EXTENDED_GLOB):
fpath=(
~/.zfuncs
~/.zfuncs/**/*~*/(CVS)#(/N)
"${fpath[@]}"
)
Это может показаться загадочным для неопытного глаза, но на самом деле он просто добавляет все каталоги ниже `~ / .zfunc 'в` $ fpath', игнорируя при этом каталоги с именем "CVS" (что полезно, если вы планируете оформить заказ целиком. дерево функций из CVS zsh в ваш личный путь поиска).
Предположим, вы получили файл `~ / .zfunc / hello ', который содержит следующую строку:
printf 'Hello world.\n'
Все, что вам нужно сделать сейчас, это отметить функцию, которая будет автоматически загружена при первом обращении к ней:
autoload -Uz hello
«Что такое -Уз?», Спросите вы? Ну, это всего лишь набор опций, которые заставят "автозагрузку" работать правильно, независимо от того, какие опции устанавливаются в противном случае. `U 'отключает расширение псевдонимов во время загрузки функции, а` z' вызывает автозагрузку в стиле zsh, даже если `KSH_AUTOLOAD 'установлен по любой причине.
После этого вы можете использовать новую функцию `hello ':
zsh% привет
Привет, мир.
Несколько слов о поиске этих файлов: это просто неправильно . Если вы поставите этот файл `~ / .zfunc / hello ', он просто напечатает« Hello world ». один раз. Ничего больше. Никакая функция не будет определена. Кроме того, идея заключается в том, чтобы загружать код функции только тогда, когда это требуется . После вызова автозагрузки определение функции не читается. Функция просто помечена для автозагрузки позже при необходимости.
И, наконец, заметка о $ FPATH и $ fpath: Zsh поддерживает их как связанные параметры. Параметр в нижнем регистре является массивом. Версия в верхнем регистре представляет собой строковый скаляр, который содержит записи из связанного массива, объединенные двоеточиями между записями. Это сделано, потому что обработка списка скаляров более естественна при использовании массивов, но при этом поддерживается обратная совместимость для кода, использующего параметр скаляра. Если вы решите использовать $ FPATH (скалярный), вам нужно быть осторожным:
FPATH=~/.zfunc:$FPATH
будет работать, а следующее не будет:
FPATH="~/.zfunc:$FPATH"
Причина в том, что расширение тильды не выполняется в двойных кавычках. Это, вероятно, источник ваших проблем. Если echo $FPATH
печатать тильду, а не расширенный путь, это не будет работать. Чтобы быть в безопасности, я бы использовал $ HOME вместо тильды, подобной этой:
FPATH="$HOME/.zfunc:$FPATH"
Тем не менее, я бы предпочел использовать параметр массива, как я сделал в верхней части этого объяснения.
Вы также не должны экспортировать параметр $ FPATH. Он нужен только текущему процессу оболочки, а не его дочерним элементам.
Обновить
Относительно содержимого файлов в `$ fpath ':
При автозагрузке в стиле zsh содержимое файла является телом функции, которую он определяет. Таким образом, файл с именем «hello», содержащий строку, echo "Hello world."
полностью определяет функцию с именем «hello». Вы можете свободно размещать
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.)