我认为一个例子最能解释我的需要
_v1="windows"
_v2_windows="/mnt/d"
_v2_osx="/Volumes/d"
echo $_v2_`echo $_v1`
_v2_windows
我想回显但使用的值来确定要获取_v1
两个中的哪一个。v2
我知道可以使用case
声明来解决问题,但我试图避免这种情况。
答案1
和zsh
:
${(P)varname}
扩展为其名称存储在 中的变量的值$varname
。因此,如果$varname
containsvar
,${(P)varname}
则扩展为与 相同的东西$var
。${(e)var}
扩展为 的内容$var
,但也在其中执行参数扩展、命令替换和算术扩展。因此,如果$var
contains$othervar
,${(e)var}
则扩展为与 相同的东西$othervar
。- 您可以嵌套变量扩展运算符,例如
${(P)${var:-something}}
工作 ${:-content}
是一种将参数扩展扩展到任意文本的方法(此处content
)
(看手册详情)
所以你可以这样做:
_v1=windows
_v2_windows=/mnt/d
printf '%s\n' ${(P)${:-_v2_$_v1}}
或者:
printf '%s\n' ${(e)${:-\$_v2_$_v1}}
或者分两步进行:
varname=_v2_$_v1
printf '%s\n' ${(P)varname}
或者:
expansions_to_evaluate=\$_v2_$_v1
printf '%s\n' ${(e)expansions_to_evaluate}
或者您可以使用标准 POSIX 语法:
eval 'printf "%s\n" "${_v2_'"$_v1"'}"'
请注意,如果 的值$_v1
不受您的控制,所有这些都相当于任意命令注入漏洞,您需要首先清理该值。
另请注意,zsh
支持关联数组(并且早在 之前就有bash
),因此您可以执行以下操作:
typeset -A mnt
mnt=(
windows /mnt/d
osx /Volumes/d
)
os=windows
printf '%s\n' $mnt[$os]
这会更清晰,并且不会产生任何安全隐患。
答案2
printf '%s\n' "${(P)$(echo "_v2_$_v1")}"
或者
var=_v2_$_v1
printf '%s\n' "${(P)var}"
在这两种情况下,参数扩展标志(P)
用于将内部名称扩展${...}
为我们想要获取其值的实际变量的名称。
这是相似的到shell${!...}
中的变量间接bash
。