2

I think a example would best explain what I need

_v1="windows"

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

echo $_v2_`echo $_v1`

I want to echo the value of _v2_windows but using _v1 to determine which of the two v2s to get.

I know can use a case statement to solve the problem but I'm trying to avoid that.

3

With zsh:

  • ${(P)varname} expands to the value of the variable whose name is stored in $varname. So if $varname contains var, ${(P)varname} expands to the same thing as $var.
  • ${(e)var} expands to the content of $var but also performs parameter expansions, command substitution and arithmetic expansion within. So if $var contains $othervar, ${(e)var} expands to the same thing as $othervar.
  • You can nest variable expansion operators, so things like ${(P)${var:-something}} work
  • ${:-content} is one way to have a parameter expansion expand to arbitrary text (here content)

(see the manual for details)

So you could do:

_v1=windows
_v2_windows=/mnt/d
printf '%s\n' ${(P)${:-_v2_$_v1}}

Or:

printf '%s\n' ${(e)${:-\$_v2_$_v1}}

Or do it in two steps:

varname=_v2_$_v1
printf '%s\n' ${(P)varname}

Or:

expansions_to_evaluate=\$_v2_$_v1

printf '%s\n' ${(e)expansions_to_evaluate}

Or you could use the standard POSIX syntax:

eval 'printf "%s\n" "${_v2_'"$_v1"'}"'

Beware that if the value of $_v1 is not under your control, all those amount to an arbitrary command injection vulnerability, you'd need to sanitize the value first.

Also note that zsh supports associative arrays (and has long before bash), so you can do:

typeset -A mnt
mnt=(
  windows /mnt/d
  osx     /Volumes/d
)
os=windows
printf '%s\n' $mnt[$os]

Which would be a lot more legible, and wouldn't have any of those security implications.

0
printf '%s\n' "${(P)$(echo "_v2_$_v1")}"

alternatively

var=_v2_$_v1
printf '%s\n' "${(P)var}"

In both cases, the parameter expansion flag (P) is used to expand the name inside ${...} into the name of the actual variable that we'd like to get the value of.

This is similar to variable indirection with ${!...} in the bash shell.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.