bash 在 zsh 中间接引用 ${!FOO} 相当于什么?

bash 在 zsh 中间接引用 ${!FOO} 相当于什么?

${!FOO}在 中执行双重替换bash,这意味着它采用 FOO 的(字符串)值并将其用作变量名。
zsh不支持此功能。

有没有办法让这个工作在bash和中相同zsh

背景:

我有一个环境变量列表,例如

PATH MAIL EDITOR

并希望首先打印变量名称,然后打印它们的值。

这适用于bash但不适用于zsh

for VAR in LIST
do
        echo $VAR
        echo ${!VAR}
done

它应该在某种程度上可能是“旧方式” eval,但我无法让它工作:

for VAR in LIST
do
        echo $VAR
        echo `eval \$$VAR`
done

我永远不会理解为什么我不能简单地进行任意深度替换,${${VAR}}或者即使${${${VAR}}}需要的话,所以对此的解释也很好。

答案1

Profpatsch 在原始问题下的评论给出了${(p)FOO}输出间接变量引用内容的示例。该标志不正确或拼写错误,它应该是大写 P 而不是小写 p。使用:${(P)FOO}

以下应该产生所需的输出:

#! /bin/zsh
LIST=(PATH MAIL EDITOR)
for VAR in ${LIST}
do
    print -r -- "${VAR}:  ${(P)VAR}"
done

来自zshexpn手册页;部分 -参数扩展标志:

  This forces the value of the parameter name to be interpreted as a further
  parameter name,  whose  value  will  be used where appropriate.  Note that
  flags set with one of the typeset family of commands (in particular case
  trans‐formations) are not applied to the value of name used in this fashion.

  If used with a nested parameter or command substitution, the result of that
  will be taken as a parameter  name  in the  same  way.   For  example,  if
  you  have  `foo=bar'  and `bar=baz', the strings ${(P)foo}, ${(P)${foo}}, and
  ${(P)$(echo bar)} will be expanded to `baz'

有一次我读到为什么${${${VAR}}}没有产生您期望的输出,但此时我找不到它。您可以执行以下操作:

first="second" ; second="third" ; third="fourth" ; fourth="fifth"
print -r -- ${(P)${(P)${(P)first}}}
fifth

答案2

bash 和 zsh 都有一种执行间接扩展的方法,但它们使用不同的语法。

使用 ; 执行间接扩展很容易eval。这适用于所有 POSIX 和大多数 Bourne shell。请注意正确引用,以防值包含在 shell 中具有特殊含义的字符。

eval "value=\"\${$VAR}\""
echo "$VAR"
echo "$value"

${${VAR}}不起作用,因为它不是任何 shell 实现的功能。大括号内的内容必须符合不包括 的语法规则${VAR}。 (在 zsh 中,这是支持的语法,但做了一些不同的事情:嵌套替换对同一值执行连续转换;${${VAR}}相当于$VAR因为这对值执行两次恒等转换。)

答案3

您没有正确使用 eval。在您的示例中,前面带有“$”(即“$VALUE”)的 $VAR 值将作为命令执行。那不是你想要的。您想要计算名称取自另一个变量的变量的扩展。

$ for i in `echo PATH MAIL EDITOR`; 
    do eval moo="\${$i}" 
    echo $moo 
done
/usr/local/sbin:/usr/local/bin:/usr/sbin:/u (...)
/var/mail/root
nano

答案4

{ba,z}sh解决方案

这是一个在 {ba,z}sh 中都有效的函数。我相信它也符合 POSIX 标准。

当给出以下信息时它会发出警告:

  • 空输入
  • 不止一个论点
  • 未设置的变量名
# Expand the variable named by $1 into its value. Works in both {ba,z}sh
# eg: a=HOME $(var_expand $a) == /home/me
var_expand() {
  if [ "$#" -ne 1 ] || [ -z "${1-}" ]; then
    printf 'var_expand: expected one non-empty argument\n' >&2;
    return 1;
  fi
  eval printf '%s' "\"\${$1?}\""
}

相关内容