user148854
user148854

Reputation: 31

Using a shell variable to choose one bash array

I am trying to write a bash script to allow me to choose one array amongst a set of different arrays. For that purpose, I intend so use a simple variable to reference that one array.

#!/bin/bash
#To get all the members of a given array as the output
#variables
FIRST=(A B C D)
SECOND=(planes cars trains bicycles gocarts)
THIRD=(werewolfs vampires zombies ghosts daemons)
FOURTH=(football soccer basketball rugby batmington zumo)
FIFTH=(handguns rifles machineguns bazookas slingshots)
SIXTH=(dogs cats turtles ferrets birds hamsters fish)
SEVENTH=(monday tuesday wednesday thursday friday saturday sunday)

#execution
select ARRAY in "FIRST" "SECOND" "THIRD" "FOURTH" "FIFTH" "SIXTH" "SEVENTH"; do 
    OUTPUT=eval '"${'${ARRAY}'[@]}"'
    echo $OUTPUT
    break 
done

#end

The above script does not work. So far, I have tried to replace line 9 with these options:

OUTPUT=eval '$'{ARRAY'[@]'}
OUTPUT=eval ${"$ARRAY"[@]}
OUTPUT=eval ${'$ARRAY'[@]}
OUTPUT=eval ${'$'ARRAY[@]}
OUTPUT=eval '$'{"$ARRAY"[@]}
OUTPUT=eval \${${ARRAY}[@]}

What am I missing here?

Upvotes: 3

Views: 230

Answers (3)

rici
rici

Reputation: 241771

eval is absolutely unnecessary to solve this problem. You should always think twice before using eval because of its fragility. (That is, an error can have disastrous consequences.)

Here's the "traditional" solution, which uses the ! indirection syntax. It's still somewhat fragile, but not as bad as eval:

select array in "FIRST" "SECOND" "THIRD" "FOURTH" "FIFTH" "SIXTH" "SEVENTH"; do
  if [[ $array ]]; then
    # Indirection requires the full subscript to be included
    # in the variable which is used to indirect. "${!array[@]}"
    # would be "0", because that is not indirect syntax; rather it
    # is "array keys" syntax.
    array_at="$array"[@]
    echo "${!array_at}"
    break
  else
    echo "Invalid input; try again" >> /dev/stderr
  fi
done

Since bash 4.3, you can use reference declarations, which make the above a little less clunky:

select name in "FIRST" "SECOND" "THIRD" "FOURTH" "FIFTH" "SIXTH" "SEVENTH"; do
  if [[ $name ]]; then
    declare -n array=name
    echo "${array[@]}"
    break
  else
    echo "Invalid input; try again" >> /dev/stderr
  fi
done
# Unless the user exits the select by typing an EOF,
# then `array` is now effectively a synonym
# for whichever of the arrays was selected.

Upvotes: 1

user148854
user148854

Reputation: 31

I got it. The following works for line 9:

OUTPUT=$(eval echo \${${ARRAY}[@]})

Thanks a lot for your patience with this poor little apprentice :)

Upvotes: 0

nicebyte
nicebyte

Reputation: 1548

This worked for me:

#!/bin/bash
#To get all the members of a given array as the output
#variables
FIRST=(A B C D)
SECOND=(planes cars trains bicycles gocarts)
THIRD=(werewolfs vampires zombies ghosts daemons)
FOURTH=(football soccer basketball rugby batmington zumo)
FIFTH=(handguns rifles machineguns bazookas slingshots)
SIXTH=(dogs cats turtles ferrets birds hamsters fish)
SEVENTH=(monday tuesday wednesday thursday friday saturday sunday)

#execution
ARRAY="FIFTH"
select ARRAY in "FIRST" "SECOND" "THIRD" "FOURTH" "FIFTH" "SIXTH" "SEVENTH"; do
    eval "OUTPUT=\${$ARRAY[*]}"
    echo $OUTPUT
    break
done

eval can be used to introduce new variables. We construct a string that contains the expression assigning the desired value to OUTPUT and then eval it, thus introducing a new variable OUTPUT with the desired value.

Upvotes: 1

Related Questions