Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm sure it is relatively simple, I just don't know how to do it.

#!/usr/bin/ksh
set `iostat`
myvar=6

I want to something like echo ${$myvar} which i want interpreted as ${$myvar} -> ${6} -> value

share|improve this question
1  
The technical term is variable indirection. –  Thor Jun 24 '12 at 13:18

4 Answers 4

up vote 8 down vote accepted

You can do this sort of thing with eval, built-in to many fine shells, including ksh:

#!/usr/bin/ksh
set $(iostat)
myvar=6
eval "echo \$$myvar"

The trick is to double-quote the string you feed to eval so that $myvar gets substituted with "6", and to backslash the outer dollar-sign, so that eval gets a string "$6".

I got "%user" for the output, but I tried it on a multi-processor RHEL machine.

share|improve this answer
    
You are officially the Supreme Exalted Grand Master of the week b/c that even works on the unfathomably awful ksh (really pdksh) in OpenBSD 5.4. If you want to set var vv to the value of the var whose name is in the var vn, just do vv=$( eval "echo \$$vn" ). Thanks a ton! –  execNext Apr 5 at 0:07

Indirect variable reference

Modern advanced shells have a method to reference the value of a variable whose name is stored in another variable. Unfortunately the method differs between ksh, bash and zsh.

In mksh ≥R39b, you can make myvar a nameref:

typeset -n myvar=6
echo "$myvar"

This doesn't work in ATT ksh93 because it doesn't support namerefs to positional parameters. In the case where you have a variable containing a variable name, you can use this method.

foo=bar
typeset -n myvar=foo
echo "$myvar"  # prints bar

In bash ≥2.0, you can write

echo "${!myvar}"

In zsh, you can write

echo ${(P)myvar}

In older shells, including ksh88 and pdksh, your only recourse when you have a variable containing another variable name and want to use the value of this variable eval, as explained by Bruce Ediger. This solution works in any Bourne/POSIX shell.

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

Using an array

This is the best method here: it's simpler and more portable.

For your use case, in any shell with arrays (all ksh variants, bash ≥2.0, zsh), you can assign to an array variable and take the element you wish. Beware that ksh and bash arrays start numbering at 0, but zsh starts at 1 unless you issue setopt ksh_arrays or emulate ksh.

set -A iostat -- $(iostat)
echo "${iostat[5]}"

If you want to copy the positional parameters to an array variable a:

set -A a -- "$@"

In ksh93, mksh ≥R39b, bash ≥2.0 and zsh, you can use the array assignment syntax:

iostat=($(iostat))
echo "${iostat[5]}"
share|improve this answer
    
Wow, your 'Bourne/POSIX' solution also works in OpenBSD 5.4's ksh/pdksh. To apply it to the example in my comment to Bruce Ediger's answer above, just do eval "vv=\${$vn}". Merci beaucoup, kind sir. –  execNext Apr 5 at 0:23

As indicated by Gilles (who provided the bash part of the answer), also not invalidating Bruce Ediger’s (on how to do it portably with eval), here’s how to do it with nameref in recent mksh (and AT&T ksh93, except – as @Gilles commented – namerefs cannot refer to positional parameters in AT&T ksh, only to named parameters):

#!/bin/mksh
set -- $(iostat)
nameref myvar=6
echo $myvar

Added the -- after set for improved resistence, too.

share|improve this answer
    
As of ksh 93u, namerefs can't reference positional parameters (typeset: 6: invalid variable name). –  Gilles Feb 27 at 14:35
    
Oh, fun. Thanks for adding! –  mirabilos Feb 27 at 14:36

Another use of arrays

Haven't used either ksh or any variant for some time, so I'm not sure if ksh(or bash) has a similar capability. My primary shell is zsh. I use arrays when handling output from commands like iostat because they produce multiple lines, and not all lines are the same format/length.

#! /bin/zsh
IOStatOutput=("${(@f)$(iostat)}") # Produces one element per line

The above also bypasses the use of positional parameters. Now, if you want to generate, say, an array of devices:

for Element in {7..${#IOStatOutput}} # Devices listed in elements 7 thru the last
do
    DevList+=( ${${=IOStatOutput[Element]}[1]} )
done

I find smaller chunks much easier to handle. You may or may not need to use indirect variable reference, depending on your code. Knowing how it works is still a good thing to know. I use it myself.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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