zsh 相当于 bash 的导出 -f 是什么

zsh 相当于 bash 的导出 -f 是什么

所以我开始使用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!

最初需要做一些工作来更新脚本,但您仍然可以在一个地方定义函数,而无需太多开销。

相关内容