bash的export -f的zsh等效项是什么


24

因此我开始使用zsh。我喜欢它。看起来很酷,很漂亮,并且当前的工作目录和实际的命令行位于不同的行是一个很好的事实,但是与此同时,我注意到这zsh可能会比慢一些bash,尤其是在将文本打印到屏幕。

我最喜欢的事情是,它zsh与我在中定义的所有功能“向后兼容” .bashrc

虽然有一个抱怨。这些功能都可以完美地工作,但是我无法弄清楚导出系统是如何工作的。

.bashrc导出了其中一些功能,以便可以在其他地方使用它们,例如在脚本和外部程序中使用export -f

在zsh中,似乎甚至没有谈论导出。它是自动加载吗?这两件事是一样的吗?我很难解决这个问题。


2
这是一个非常老的问题,但是我想说“当前的工作目录和实际的命令行在不同的行上”与zsh完全无关。取决于您如何设置提示,仅此而已。
4ae1e1 2014年

Answers:


11

包含函数的环境变量是bash hack。Zsh没有类似的东西。您可以使用几行代码来执行类似的操作。环境变量包含字符串;在发现Shellshock之前,较早的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的原始发现者StéphaneChazelas指出的那样,如果函数定义的格式有误,此答案的早期版本此时可以执行任意代码。该版本没有,但是当然只要您执行任何命令,它可能是从环境导入的函数。)

在环境中使用无效的变量名(例如BASH_FUNC_myfunc%%)对bash的Shellshock后版本进行编码。由于zsh没有提供从环境中提取此类变量名称的接口,因此这使它们更难以可靠地解析。

我不建议这样做。依靠脚本中的导出函数是一个坏主意:它在脚本中创建了不可见的依赖关系。如果您曾经在没有功能的环境中运行脚本(在更改了外壳初始化文件后,在另一台计算机上,在cron作业中,…),则该脚本将不再起作用。而是将所有函数存储在一个或多个单独的文件中(如~/lib/shell/foo.sh),然后通过导入其使用的函数(. ~/lib/shell/foo.sh)来启动脚本。这样,如果您进行修改foo.sh,则可以轻松地搜索依赖它的脚本。如果您复制脚本,则可以轻松找出它需要哪些辅助文件。

Zsh(及其之前的ksh)通过提供一种在使用脚本的函数中自动加载函数的方式,使此操作更加方便。约束是每个文件只能放置一个函数。将函数声明为自动加载,并将函数定义放入名称为函数名称的文件中。将此文件放置在中列出的目录中$fpath(您可以通过FPATH环境变量进行配置)。在脚本中,使用声明自动加载的函数autoload -U foo

此外,zsh可以编译脚本,以节省解析时间。调用zcompile以编译脚本。这将创建带有.zwc扩展名的文件。如果存在此文件,autoload则将加载编译的文件而不是源代码。您可以使用该zrecompile函数来(重新)编译目录中的所有函数定义。


1
有趣的是,您的代码具有相同的shellshock漏洞bash(不验证变量的内容是函数定义,并且不处理任何变量名称,如HTTP_HOSTLC_X)。否则,好的答案。
斯特凡Chazelas

@StéphaneChazelas如果您要运行带有从环境中导入的功能的命令,那么您几乎会迷失方向。但是我已经更新了导入代码,以不执行任意代码。但是,它不是很有用,因为后shellshock bash不会以相同的方式编码其导出的函数。
吉尔斯(Gillles)“所以-别再邪恶了”

您现在已经修复了等效的CVE-2014-6271,但仍可能会遇到许多CVE-2014-6277 / 6278类型的漏洞...因为您仍在向zsh解析器公开任何变量中的代码包括一些在某些情况下可能受到攻击者控制的代码(因为即使从未调用该函数,zsh -c 'functions[f]=$VAR' 也会解析其中的代码f)。解决方案是仅考虑名称遵循保留模板的变量,例如那些$BASH_FUNC_x%%,但正如您所说的,zsh没有列出或检索这些变量的API。您需要致电perl例如。
斯特凡Chazelas

7

如果将函数声明放在.zshenv中,则可以轻松地从脚本使用函数。


你为什么反对我的回答?请解释。
rools

仍在等待答案,仍在工作!
rools

我刚刚发现了这个答案,这是一个理想的解决方案。
AFH 2018年

我没有投票。OP TBH询问从.bashrc导出内容的想法,这是一个坏主意,最好将其放在脚本中,以免最终没有庞大的环境。但是您的解决方案只是这个坏主意的一个变体,将所有脚本放入其中,.zshenv并通过解析大量从未使用过的代码来减慢每次zsh的调用。此外,它与导出函数不同,就像导出的变量一样,导出的函数仅可用于子进程。而您放入的.zshenv内容可用于每个zsh。
变态的

最后,如果您依靠自己输入的个人代码.zshenv,那么所有脚本都将完全不可移植。通常,脚本可能会相互依赖,这很好,您可以将它们分发在一起。但是,如果它们依赖于中的特殊功能.zshenv,则没有人会想要使用它们,或者必须使用特殊的调用它们ZDOTDIR,从而阻止您自己的函数.zshenv被执行。会很痛苦的。
变形的
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.