zsh:通过引用传递变量,并修改其值(如 bash 的 local -n namerefs)?

cod*_*oet 5 shell bash zsh shell-script function

是否可以将变量传递给 zsh 函数,并在不使用 eval 的情况下修改其值?我遇到了一种 bash 方法来做到这一点:: https local -n: //stackoverflow.com/a/50281697

Sté*_*las 8

typeset -n实际上最初来自 ksh93 (1993)。bash 在 2014 年发布的 4.3 中添加了类似的内容。在 ksh93 中,它更有用,因为 ksh93 执行静态作用域(您无法从调用者访问局部变量,除非它们被导出),而不是 bash 中的动态作用域/zsh (其中函数始终看到其调用者\xc2\xb9 的局部变量)。也可以看看:

\n
$ bash -c \'function f { typeset -n var=$1; var=x;}; var=0; f var; echo "$var"\'\nenvironment: line 0: typeset: warning: var: circular name reference\nenvironment: warning: var: circular name reference\nenvironment: warning: var: circular name reference\nx\n$ ksh -c \'function f { typeset -n var=$1; var=x;}; var=0; f var; echo "$var"\'\nx\n
Run Code Online (Sandbox Code Playgroud)\n

zsh 没有 nameref 支持,尽管它有变量取消引用运算符,可用于扩展和赋值。

\n
$ expand() print -r -- ${(P)1}\n$ assign() : ${(P)1::=$2}\n$ var=foo\n$ expand var\nfoo\n$ assign var bar\n$ print -r -- $var\nbar\n
Run Code Online (Sandbox Code Playgroud)\n

或者您始终可以使用标准方法,eval该方法应该在任何类似 Bourne 的 shell 中工作:

\n
expand() {\n  eval \'printf "%s\\n" "${\'"$1"\'}"\'\n}\nassign() {\n  eval "$1=\\$2"\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在你问之前,不,这并不比P在 bash 中使用标志或 namerefs 更不安全,只要它像这里一样正确完成。无论采用哪种方法,正确控制变量名称都很重要。

\n

assign var "$external_input"无论您使用、 namerefs 还是 ,assign "$external_input" value是否安全。与with或which相同,都是bash/ksh/zsh 中的任意命令执行漏洞。expand "$external_input"Peval[ -v "$external_input" ]read "$external_input"

\n

另请参阅zsh-workers 邮件列表上关于进行间接分配的各种方法的优点的讨论。

\n

2001 年的讨论正在考虑向 zsh 添加 ksh93 风格的 nameref 支持。2015 年和 2023 年再次出现表明人们有兴趣添加该功能,并且最终可能会在 5.9 之后的下一个版本中添加该功能,无论是 5.10 还是 6.0 。

\n
\n

\xc2\xb9 尽管请参阅zsh/param/private模块zsh以将变量变为函数私有。

\n