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 can do this, but it requires making a string of the variable then dereferencing it. Is there any way to shorten it to a simpler statement?

#!/bin/bash

FRUITS="BANANA APPLE ORANGE"

BANANA_COLOUR="Yellow"
APPLE_COLOUR="Green or Red"
ORANGE_COLOUR="Blue"

for fruit in $( echo $FRUITS ); do
    fruit_colour="${fruit}_COLOUR"
    echo $fruit is ${!fruit_colour}
done

I have tried lots of things like ${!"${fruit}_COLOUR"} or \$${fruit}_COLOUR and many other variants, but the only way that has worked is by using a string.

share|improve this question
    
The ! syntax is a flag on variable substitution that basically says “substitute twice”. It doesn't change the requirement that what's inside the ${…} must be a variable name. So no, you can't avoid using a variable that contains the name, unless you use a different method (eval). –  Gilles Feb 21 '12 at 0:31
    
You can also use associative arrays to do this much more cleanly. However its not a direct answer to your question, so just adding it as a comment. –  Patrick Feb 21 '12 at 1:29

2 Answers 2

up vote 7 down vote accepted

Fiirst off, you don't need to use $(echo $FRUITS) in the for statement. Using just $FRUITS is enough. Then you can do away with one of the lines inside the loop, by using eval.

The eval simply tells bash to make a second evaluation of the following statement (ie. one more that its normal evaluation).. The \$ survives the first evaluation as $, and the next evaluation then treats this $ as the start of a variable name, which resolves to "Yellow", etc..

This way you don't need to have a seperate step which makes an interim string (which is what I believe was the main intent of your question).

for fruit in $FRUITS ;do
    eval echo $fruit is \$${fruit}_COLOUR
done

For an alternative method, as mentioned by Patrick in a comment (above), you can instead use an associative array, in which an element's index does not neeed to be an integer. You can use a string, such as tne name of a type of fruit. Here is an example, using bash's associative array,

# This declares an associative array (It unsets it if it already exists)
declare -A colour
colour['BANANA']="Yellow"
colour["APPLE"]="Green or Red"
colour[MARTIAN ORANGE]="Blue"

for fruit in BANANA APPLE "MARTIAN ORANGE" ;do 
    echo "$fruit" is "${colour[$fruit]}"
done
share|improve this answer

You can use the bash-builtin eval to do that:

#!/bin/bash
FRUITS="BANANA APPLE ORANGE"
BANANA_COLOUR="Yellow"
APPLE_COLOUR="Green or Red"
ORANGE_COLOUR="Blue"

for fruit in $( echo $FRUITS );
do
    fruit_colour=${fruit}_COLOUR
    eval echo $fruit is \$${fruit_colour}
done

Note the backslashed-dollar sign. Basically, the "eval" line causes bash to substitue for $fruit and ${fruit_color}, then using eval to do a second round of substition before calling echo.

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.