bash 和 zsh 中的双重和三重替换

bash 和 zsh 中的双重和三重替换

后续后台部分这个问题

bashI 中可以用于${!FOO}双重替换,在zsh ${(P)FOO}.在这两种情况下,老派(hack-y)eval \$$FOO都有效。

所以,对我来说最聪明、最合乎逻辑的事情是${${FOO}}, ${${${FOO}}}…双/三/n 替换。为什么这不能按预期工作?

第二:声明\中的作用是什么eval?我认为这是一种逃避,让事情变得eval \$$$FOO不可能。如何使用在每个 shell 中都有效的三重/n 替换?

答案1

必须\用于防止$$(当前进程 ID)的扩展。对于三重替换,您需要双重 eval,因此还需要更多转义以避免每个 eval 中不必要的扩展:

#! /bin/bash
l0=value
l1=l0
l2=l1
l3=l2
l4=l3

echo $l0
eval echo \$$l1
eval eval echo \\$\$$l2
eval eval eval echo \\\\$\\$\$$l3
eval eval eval eval echo \\\\\\\\$\\\\$\\$\$$l4

答案2

#!/bin/bash

hello=world
echo=hello

echo $echo ${!echo}

答案3

假设 的值FOO是有效的变量名(例如BAR),eval \$$FOO将 的值拆分BAR为单独的单词,将每个单词视为通配符模式,并将结果的第一个单词作为命令执行,将其他单词作为参数传递。美元前面的反斜杠使其按字面意思处理,因此传递给eval内置函数的参数是四字符字符串$BAR

${${FOO}}是一个语法错误。它不执行“双重替换”,因为任何常见 shell 中都没有这样的功能(无论如何都不使用此语法)。在 zsh 中,${${FOO}} 有效并且是双重替换,但它的行为与您想要的不同:它对 的值执行两次连续的转换FOO,这两个转换都是恒等转换,所以它只是一种奇特的编写方式${FOO}

如果您想将变量的值视为变量,请注意正确引用内容。如果将结果设置为变量会容易得多:

eval "value=\${$FOO}"

答案4

你为什么需要这么做?

您始终可以通过几个步骤来完成此操作,例如:

eval "l1=\${$var}"
eval "l2=\${$l1}"
...

或者使用如下函数:

deref() {
  if [ "$1" -le 0 ]; then
    eval "$3=\$2"
  else
    eval "deref $(($1 - 1)) \"\${$2}\" \"\$3\""
  fi
}

然后:

$ a=b b=c c=d d=e e=blah
$ deref 3 a res; echo "$res"
d
$ deref 5 a res; echo "$res"
blah

FWIW,在zsh

$ echo ${(P)${(P)${(P)${(P)a}}}}
blah

相关内容