First 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 (i.e. one more than 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 separate 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 need to be an integer. You can use a string, such as the 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
!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).