zsh:如何根据另一个变量获取变量的值?

zsh:如何根据另一个变量获取变量的值?

我认为一个例子最能解释我的需要

_v1="windows"

_v2_windows="/mnt/d"
_v2_osx="/Volumes/d"

echo $_v2_`echo $_v1`

_v2_windows我想回显但使用的值来确定要获取_v1两个中的哪一个。v2

我知道可以使用case声明来解决问题,但我试图避免这种情况。

答案1

zsh

  • ${(P)varname}扩展为其名称存储在 中的变量的值$varname。因此,如果$varnamecontains var${(P)varname}则扩展为与 相同的东西$var
  • ${(e)var}扩展为 的内容$var,但也在其中执行参数扩展、命令替换和算术扩展。因此,如果$varcontains $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

相关内容