Мне трудно определить и запустить свои собственные функции оболочки в Zsh. Я следовал инструкциям на официальной документации и сначала попробовал простой пример, но мне не удалось это сделать.
У меня есть папка:
~/.my_zsh_functions
В этой папке у меня есть файл functions_1
с rwx
разрешениями пользователя. В этом файле я определил следующую функцию оболочки:
my_function () {
echo "Hello world";
}
Я определил, FPATH
чтобы включить путь к папке ~/.my_zsh_functions
:
export FPATH=~/.my_zsh_functions:$FPATH
Я могу подтвердить, что папка .my_zsh_functions
находится в пути функций с помощью echo $FPATH
илиecho $fpath
Однако, если я тогда попробую следующее из оболочки:
> autoload my_function
> my_function
Я получил:
zsh: my_test_function: файл определения функции не найден
Есть ли что-то еще, что мне нужно сделать, чтобы иметь возможность позвонить my_function
?
Обновить:
Ответы до сих пор предполагают поиск файла с помощью функций zsh. Это имеет смысл, но я немного растерялся. Разве zsh не должен знать, где находятся эти файлы FPATH
? Какова цель autoload
тогда?
источник
Ответы:
В zsh путь поиска функции ($ fpath) определяет набор каталогов, которые содержат файлы, которые могут быть помечены для автоматической загрузки, когда функция, которую они содержат, требуется в первый раз.
Zsh имеет два режима автозагрузки файлов: собственный способ Zsh и другой режим, который напоминает автозагрузку ksh. Последний активен, если установлена опция KSH_AUTOLOAD. Нативный режим Zsh используется по умолчанию, и я не буду обсуждать здесь другие способы (см. «Man zshmisc» и «man zshoptions» для получения подробной информации о автозагрузке в стиле ksh).
Хорошо. Скажем, у вас есть каталог `~ / .zfunc ', и вы хотите, чтобы он был частью пути поиска функции, вы делаете это:
Это добавляет ваш личный каталог в передней части пути поиска. Это важно, если вы хотите переопределить функции из установки zsh своей собственной (например, когда вы хотите использовать обновленную функцию завершения, такую как _git из репозитория zsh CVS, с более старой установленной версией оболочки).
Стоит также отметить, что каталоги из $ fpath не ищутся рекурсивно. Если вы хотите, чтобы ваш личный каталог подвергался рекурсивному поиску, вам придется позаботиться об этом самостоятельно, как показано ниже (в следующем фрагменте кода должна быть задана опция EXTENDED_GLOB):
Это может показаться загадочным для неопытного глаза, но на самом деле он просто добавляет все каталоги ниже `~ / .zfunc 'в` $ fpath', игнорируя при этом каталоги с именем "CVS" (что полезно, если вы планируете оформить заказ целиком. дерево функций из CVS zsh в ваш личный путь поиска).
Предположим, вы получили файл `~ / .zfunc / hello ', который содержит следующую строку:
Все, что вам нужно сделать сейчас, это отметить функцию, которая будет автоматически загружена при первом обращении к ней:
«Что такое -Уз?», Спросите вы? Ну, это всего лишь набор опций, которые заставят "автозагрузку" работать правильно, независимо от того, какие опции устанавливаются в противном случае. `U 'отключает расширение псевдонимов во время загрузки функции, а` z' вызывает автозагрузку в стиле zsh, даже если `KSH_AUTOLOAD 'установлен по любой причине.
После этого вы можете использовать новую функцию `hello ':
Несколько слов о поиске этих файлов: это просто неправильно . Если вы поставите этот файл `~ / .zfunc / hello ', он просто напечатает« Hello world ». один раз. Ничего больше. Никакая функция не будет определена. Кроме того, идея заключается в том, чтобы загружать код функции только тогда, когда это требуется . После вызова автозагрузки определение функции не читается. Функция просто помечена для автозагрузки позже при необходимости.
И, наконец, заметка о $ FPATH и $ fpath: Zsh поддерживает их как связанные параметры. Параметр в нижнем регистре является массивом. Версия в верхнем регистре представляет собой строковый скаляр, который содержит записи из связанного массива, объединенные двоеточиями между записями. Это сделано, потому что обработка списка скаляров более естественна при использовании массивов, но при этом поддерживается обратная совместимость для кода, использующего параметр скаляра. Если вы решите использовать $ FPATH (скалярный), вам нужно быть осторожным:
будет работать, а следующее не будет:
Причина в том, что расширение тильды не выполняется в двойных кавычках. Это, вероятно, источник ваших проблем. Если
echo $FPATH
печатать тильду, а не расширенный путь, это не будет работать. Чтобы быть в безопасности, я бы использовал $ HOME вместо тильды, подобной этой:Тем не менее, я бы предпочел использовать параметр массива, как я сделал в верхней части этого объяснения.
Вы также не должны экспортировать параметр $ FPATH. Он нужен только текущему процессу оболочки, а не его дочерним элементам.
Обновить
Относительно содержимого файлов в `$ fpath ':
При автозагрузке в стиле zsh содержимое файла является телом функции, которую он определяет. Таким образом, файл с именем «hello», содержащий строку,
echo "Hello world."
полностью определяет функцию с именем «hello». Вы можете свободно размещатьhello () { ... }
код, но это было бы излишним.Однако утверждение, что один файл может содержать только одну функцию, не совсем корректно.
Особенно если вы посмотрите на некоторые функции из системы завершения, основанной на функциях (compsys), вы быстро поймете, что это заблуждение. Вы можете определить дополнительные функции в файле функций. Вы также можете выполнять любую инициализацию, которая может потребоваться при первом вызове функции. Однако, когда вы это сделаете, вы всегда определите функцию, которая названа как файл в файле, и вызовите эту функцию в конце файла, так что она будет запущена при первом обращении к функции.
Если - с подфункциями - вы не определили функцию, названную как файл в файле, вы бы в конечном итоге получили эту функцию с определениями функций в ней (а именно с теми из подфункций в файле). Вы бы эффективно определяли все свои подфункции каждый раз, когда вызываете функцию с именем, подобным файлу. Обычно это не то, что вам нужно, поэтому вы должны переопределить функцию, которая называется как файл в файле.
Я включу короткий скелет, который даст вам представление о том, как это работает:
Если вы запустите этот глупый пример, первый запуск будет выглядеть так:
И последовательные звонки будут выглядеть так:
Я надеюсь, что это проясняет ситуацию.
(Один из более сложных реальных примеров, использующих все эти приемы, - это уже упоминавшаяся функция _tmux из системы завершения, основанной на функциях zsh.)
источник
my_function () { }
в вашемHello world
примере. Если синтаксис не нужен, когда будет полезно его использовать?Имя файла в каталоге, названном
fpath
элементом, должно совпадать с именем функции автозагрузки, которую он определяет.Ваша функция названа
my_function
и~/.my_zsh_functions
является предполагаемой директорией в вашейfpath
, поэтому определениеmy_function
должно быть в файле~/.my_zsh_functions/my_function
.Множественное число в предложенном вами имени файла (
functions_1
) указывает, что вы планируете поместить в файл несколько функций. Это не так, какfpath
и автозагрузка работы. Вы должны иметь одно определение функции для каждого файла.источник
дайте
source ~/.my_zsh_functions/functions1
в терминал и оценитеmy_function
, теперь вы сможете вызывать функциюисточник
FPATH
иautoload
тогда? Зачем мне также нужен исходный файл? Смотрите мой обновленный вопрос.Вы можете «загрузить» файл со всеми вашими функциями в ваш $ ZDOTDIR / .zshrc следующим образом:
Или можете использовать точку "." вместо «источника».
источник
FPATH
иautoload
тогда? Зачем мне также нужен исходный файл? Смотрите мой обновленный вопрос.Sourcing определенно не является правильным подходом, так как вам кажется, что нужно иметь ленивые инициализированные функции. Вот для чего
autoload
. Вот как вы делаете то, что вы после.В вашем
~/.my_zsh_functions
, вы говорите, что хотите поместить функцию под названиемmy_function
«Привет, мир». Но вы заключаете его в вызов функции, а это не так. Вместо этого вам нужно создать файл с именем~/.my_zsh_functions/my_function
. В нем, просто положитьecho "Hello world"
, а не в обертку функции. Вы также можете сделать что-то вроде этого, если вы действительно предпочитаете иметь обертку.Далее в вашем
.zshrc
файле добавьте следующее:Когда вы загрузите новую оболочку ZSH, введите
which my_function
. Вы должны увидеть это:ZSH только что отключил my_function для вас
autoload -X
. Теперь беги,my_function
но просто печатайmy_function
. Вы должны увидетьHello world
распечатку, и теперь, когда вы запустите,which my_function
вы увидите заполненную функцию следующим образом:Теперь настоящая магия приходит, когда вы настраиваете всю свою
~/.my_zsh_functions
папку для работыautoload
. Если вы хотите, чтобы каждый файл, который вы перетащили в эту папку, работал так, измените то, что вы положили в него,.zshrc
на что-то такое:источник