所以我开始使用zsh
.我喜欢这一切。它看起来非常酷和光滑,而且当前工作目录和实际命令行位于不同的行这一事实很好,但同时,我注意到它zsh
可能比 慢一点bash
,特别是在将文本打印到屏幕。
我最喜欢的一点是它zsh
与我在.bashrc
.
不过有一点抱怨。所有功能都运行良好,但我不知道导出系统是如何工作的。
我导出了其中一些.bashrc
函数,以便我可以在其他地方使用它们,例如在脚本和外部程序中,通过export -f
.
在 zsh 中,似乎甚至没有谈论导出。是自动加载吗?这两件事是一样的吗?我很难弄清楚这一点。
答案1
包含函数的环境变量是 bash hack。 Zsh 没有类似的东西。您可以使用几行代码完成类似的操作。环境变量包含字符串;旧版本的 bash,之前炮弹休克被发现,将函数的代码存储在一个变量中,该变量的名称是函数的名称,其值() {
后面是函数代码,后面是}
.您可以使用以下代码导入具有此编码的变量,并尝试使用类似 bash 的设置运行它们。请注意,zsh 无法模拟所有 bash 功能,您所能做的就是更接近一点(例如,分割$foo
值并扩展通配符,并使数组从 0 开始)。
bash_function_preamble='
emulate -LR ksh
'
for name in ${(k)parameters}; do
[[ "-$parameters[name]-" = *-export-* ]] || continue
[[ ${(P)name} = '() {'*'}' ]] || continue
((! $+builtins[$name])) || continue
functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done
(作为斯蒂芬·查泽拉斯Shellshock 的原始发现者指出,如果函数定义格式错误,此答案的早期版本可能会在此时执行任意代码。这个版本没有,但是当然,一旦您执行任何命令,它可能是从环境导入的函数。)
bash 后 Shellshock 版本使用无效变量名称(例如BASH_FUNC_myfunc%%
)对环境中的函数进行编码。这使得它们更难可靠地解析,因为 zsh 不提供从环境中提取此类变量名称的接口。
我不建议这样做。依赖脚本中的导出函数是一个坏主意:它会在脚本中创建不可见的依赖关系。如果您曾经在没有您的功能的环境中运行脚本(在另一台机器上、在 cron 作业中、在更改 shell 初始化文件之后……),您的脚本将不再工作。相反,请将所有函数存储在一个或多个单独的文件(类似于~/lib/shell/foo.sh
)中,并通过导入脚本使用的函数来启动脚本 ( . ~/lib/shell/foo.sh
)。这样,如果您修改foo.sh
,您可以轻松搜索哪些脚本依赖于它。如果复制脚本,您可以轻松找到它需要哪些辅助文件。
Zsh(以及之前的 ksh)通过提供一种在使用函数的脚本中自动加载函数的方法,使这变得更加方便。限制是每个文件只能放置一个函数。将函数声明为自动加载,并将函数定义放在名称为函数名称的文件中。将此文件放在列出的目录中$fpath
(您可以通过FPATH
环境变量进行配置)。在您的脚本中,使用 .声明自动加载的函数autoload -U foo
。
此外zsh可以编译脚本,以节省解析时间。称呼zcompile
编译脚本。这将创建一个具有扩展名的文件.zwc
。如果此文件存在,autoload
则将加载已编译的文件而不是源代码。您可以使用zrecompile
功能(重新)编译目录中的所有函数定义。
答案2
如果你把你的函数声明放在.zshenv,您的函数将可以从脚本中使用,无需任何努力。
答案3
我读过的所有内容都表明自动导入函数是一个坏主意,因此我决定将脚本提取到一个单独的文件中,该文件可以在子 shell 中轻松获取。
我调用了共享文件.zshared
。
# ~/.zshared
function say-hello() {
echo "Hello, $1\!"
}
我将其来源在我的.zshrc
.
# ~/.zshrc
source ~/.zshared
在任何需要访问这些函数的脚本中,我只需 source .zshared
.
#!/usr/bin/env zsh
source ~/.zshared
say-hello "David" # Hello, David!
最初需要做一些工作来更新脚本,但您仍然可以在一个地方定义函数,而无需太多开销。