在zsh中,函数搜索路径($ fpath)定义了一组目录,其中包含一些文件,可以将这些文件标记为在首次需要包含它们的功能时自动加载。
Zsh具有两种自动加载文件的模式:Zsh的本机方式和另一种类似于ksh自动加载的方式。如果设置了KSH_AUTOLOAD选项,则后者处于活动状态。Zsh的本机模式是默认模式,在这里我不再讨论其他方式(有关ksh样式自动加载的详细信息,请参见“ man zshmisc”和“ man zshoptions”)。
好的。假设您有一个目录〜/ .zfunc,并且希望它成为函数搜索路径的一部分,请执行以下操作:
fpath=( ~/.zfunc "${fpath[@]}" )
这会将您的私有目录添加到搜索路径的前面。如果您想用自己的方法覆盖zsh安装程序中的功能(例如,当您要使用更新的完成功能,例如来自zsh CVS存储库中的“ _git”,以及较旧的Shell版本)时,这一点很重要。
还值得注意的是,`$ fpath'中的目录不是递归搜索的。如果要递归搜索私有目录,则必须自己进行处理,如下所示(以下代码段需要设置“ EXTENDED_GLOB”选项):
fpath=(
~/.zfuncs
~/.zfuncs/**/*~*/(CVS)#(/N)
"${fpath[@]}"
)
对于未经培训的人来说,它看起来似乎很神秘,但是实际上它只是将〜/ .zfunc下面的所有目录添加到$ fpath中,而忽略了称为“ CVS”的目录(如果您打算整体检出,这很有用。从zsh的CVS到您的私有搜索路径的功能树)。
假设您有一个文件~~ ..zfunc / hello,其中包含以下行:
printf 'Hello world.\n'
您现在需要做的就是标记该函数,使其在首次引用时自动加载:
autoload -Uz hello
“你问-Uz是什么?”?好吧,这只是一组选项,无论设置了什么选项,都会导致“自动加载”执行正确的操作。“ U”会在函数加载时禁用别名扩展,即使由于任何原因设置了“ KSH_AUTOLOAD”,“ z”也会强制执行zsh样式的自动加载。
处理完之后,您可以使用新的`hello'函数:
zsh%你好
你好,世界。
关于采购这些文件的一句话:这是错误的。如果您要获取`〜/ .zfunc / hello'文件,它将仅显示“ Hello world”。一旦。而已。不会定义任何功能。此外,其想法是仅在需要时加载函数的代码。调用“ autoload”后,不会读取该函数的定义。该功能只是标记为以后需要时自动加载。
最后,关于$ FPATH和$ fpath的注释:Zsh将它们保留为链接参数。小写参数是一个数组。大写版本是字符串标量,包含链接数组中的条目,条目之间由冒号相连。这样做是因为使用数组处理标量列表更为自然,同时还可以维护使用标量参数的代码的向后兼容性。如果选择使用$ FPATH(标量之一),则需要小心:
FPATH=~/.zfunc:$FPATH
将起作用,而以下情况将不起作用:
FPATH="~/.zfunc:$FPATH"
原因是没有在双引号内执行波浪号扩展。这可能是您问题的根源。如果echo $FPATH
打印波浪号而不是扩展路径,则它将不起作用。为了安全起见,我将使用$ HOME代替这样的波浪号:
FPATH="$HOME/.zfunc:$FPATH"
话虽如此,我宁愿像在此解释顶部一样使用array参数。
您也不应导出$ 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%你好
你好,世界。
我希望这可以解决问题。
(使用所有这些技巧的更复杂的现实示例之一是zsh基于函数的完成系统中已经提到的` _tmux函数。)