Как определить и загрузиться, Ваша собственная оболочка функционируют в zsh

Я верю актуальнейшим версиям man будет DoTheRightThing™ при определении страницы справочника как аргумента, содержащего наклонную черту:

man ./stuff.1

58
02.03.2012, 20:16
5 ответов

В zsh функциональный путь поиска ($fpath) определяет ряд каталогов, которые содержат файлы, которые могут быть отмечены, чтобы быть загруженными автоматически, когда функция, которую они содержат, необходима впервые.

Zsh имеет два режима файлов с автозагрузкой: собственный путь Zsh и другой режим, который напоминает автозагрузку ksh. Последний активен, если опция KSH_AUTOLOAD установлена. Режим работы в собственной системе команд Zsh является значением по умолчанию, и я не буду обсуждать другой путь здесь (см. "человека zshmisc" и "человека 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' отключает расширение псевдонима, в то время как функция загружается и автозагрузка zsh-стиля сил 'z', даже если 'KSH_AUTOLOAD' установлен по любой причине.

После этого заботился о, можно использовать новое, 'привет' функционируйте:

zsh% hello
Hello world.

Слово об определении источника этих файлов: это просто неправильно. При определении источника этого '~/.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% hello
initialising...
Hello world.

И последующие вызовы будут похожи на это:

zsh% hello
Hello World.

Я надеюсь, что это разрешает вещи.

(Одним из более сложных реальных примеров, который использует все те приемы, является уже упомянутая функция '_tmux' от основанной на функции системы завершения zsh.)

98
27.01.2020, 19:32
  • 1
    Спасибо Frank! Я читал в других ответах, что я могу только определить одну функцию на файл, который является правильным? Я заметил, что Вы не использовали синтаксис my_function () { } в Вашем Hello world пример. Если бы синтаксис не нужен, когда было бы полезно использовать его? –  Amelio Vazquez-Reina 10.03.2012, 22:26
  • 2
    я расширил исходный ответ для рассматривания тех вопросов также. –  Frank Terbeck 11.03.2012, 00:43
  • 3
    “ Вы будете всегда определять в функции, которую называют как файл в файле, и вызовите ту функцию в конце файла”:как же так? –  Hibou57 14.08.2014, 00:39
  • 4
    Hibou57: (В стороне: это - опечатка там, должен быть, "определяют функцию", это фиксируется теперь.) Я думал, что это было ясно при взятии фрагмента кода, который следует к рассмотрению. Так или иначе я добавил абзац, который записывает причину немного более буквально. –  Frank Terbeck 15.08.2014, 15:04
  • 5
    Вот больше информации от Вашего сайта, спасибо. –  Timo 07.11.2017, 17:25

Название файла в каталоге, названном fpath элемент должен соответствовать названию автозагружаемой функции, которую это определяет.

Вашу функцию называют my_function и ~/.my_zsh_functions намеченный каталог в Вашем fpath, так определение my_function должен быть в файле ~/.my_zsh_functions/my_function.

Множественное число в Вашем предложенном имени файла (functions_1) указывает, что Вы были планированием помещения нескольких функций в файле. Это не то, как fpath и автозагрузка работы. У Вас должно быть одно функциональное определение на файл.

5
27.01.2020, 19:32

дать source ~/.my_zsh_functions/functions1 в терминале и оценивании my_function, теперь Вы сможете вызвать функцию

2
27.01.2020, 19:32
  • 1
    Спасибо, но из чего роль FPATH и autoload затем? Почему я должен также получить файл? Посмотрите мой обновленный вопрос. –  Amelio Vazquez-Reina 02.03.2012, 20:17

Можно "загрузить" файл всеми функциями в $ZDOTDIR/.zshrc как это:

source $ZDOTDIR/functions_file

Или может использовать точку "." вместо "источника".

1
27.01.2020, 19:32
  • 1
    Благодарит, но из чего роль FPATH и autoload затем? Почему я должен также получить файл? Посмотрите мой обновленный вопрос. –  Amelio Vazquez-Reina 02.03.2012, 20:16

Использование сорсинга определенно не является правильным подходом, так как вы, кажется, хотите иметь ленивые инициализированные функции. Вот для чего autoload. Вот как вы достигаете того, что вам нужно.

В своем ~/.my_zsh_functionsвы говорите, что хотите поместить функцию с именем my_function, которая повторяет "hello world". Но вы оборачиваете его в вызов функции, а это не так. Вместо этого вам нужно создать файл с именем ~/.my_zsh_functions/my_function. В нем просто поместите echo "Hello world", а не в обёртку функции. Вы также можете сделать что-то подобное, если вы действительно предпочитаете иметь обертку.

# ~/.my_zsh_functions/my_function
__my_function () {
    echo "Hello world";
}
# you have to call __my_function
# if this is how you choose to do it
__my_function

Затем в файле .zshrcдобавьте следующее:

fpath=(~/.my_zsh_functions $fpath);
autoload -U ~/.my_zsh_functions/my_function

При загрузке новой оболочки ZSH введите which my_function. Вы должны увидеть это:

my_function () {
    # undefined
    builtin autoload -XU
}

ZSH только что заглушил для вас мою функцию _с помощью autoload -X. Сейчас,запустите my_function, просто набрав my_function. Вы должны увидеть распечатку Hello world, и теперь, когда вы запустите which my_function, вы должны увидеть функцию, заполненную следующим образом:

my_function () {
    echo "Hello world"
}

Настоящее волшебство начинается, когда вы настраиваете всю папку ~/.my_zsh_functionsдля работы с autoload. Если вы хотите, чтобы каждый файл, который вы перетаскиваете в эту папку, работал так, измените то, что вы помещаете в свой .zshrc, на что-то такое:

# add ~/.my_zsh_functions to fpath, and then lazy autoload
# every file in there as a function
fpath=(~/.my_zsh_functions $fpath);
autoload -U $fpath[1]/*(.:t)
8
27.01.2020, 19:32

Теги

Похожие вопросы