3

I'm writing a Bash script to simplify file copies from our main site to multiple agencies. In this script, I'm trying to use a variable as an associative array name but I optain an error, here is the code :

#!/bin/bash

declare -A GROUP1
declare -A GROUP2
declare -A GROUP3
declare -A ARRAY

GROUP1["SITE1"]="x.x.x.x"
GROUP1["SITE2"]="y.y.y.y"
GROUP1["SITE3"]="z.z.z.z"

GROUP2["SITE1"]="1.1.1.1"
GROUP2["SITE2"]="2.2.2.2"
GROUP2["SITE3"]="3.3.3.3"

GROUP2["SITE1"]="a.a.a.a"
GROUP2["SITE2"]="b.b.b.b"
GROUP2["SITE3"]="c.c.c.c"

read -p "Choose a group of sites : " group

case $group in
    1 ) DEST="GROUP1" ;;
    2 ) DEST="GROUP2" ;;
    3 ) DEST="GROUP3" ;;
esac

eval "ARRAY=(\${$DEST[@]})"

for elem in "${!ARRAY[@]}"
do
   echo $elem
   echo ${ARRAY[$elem]}
done

Here is the error :

./test: line28: TAB : 3.3.3.3 : must use subscript when assigning associative array
./test: line28: TAB : 2.2.2.2 : must use subscript when assigning associative array
./test: line28: TAB : 1.1.1.1 : must use subscript when assigning associative array

Is what I am trying to do possible ? Thanks in advance.

Jaymzwise
  • 31
  • 5

1 Answers1

2

It's possible but it's not easy unless you have bash v4.3. With 4.3, you can use a "nameref":

declare -A GROUP1
declare -A GROUP2
declare -A GROUP3

GROUP1["SITE1"]="x.x.x.x"
#...

# Yuk. Use command-line options, not stdin
read -p "Choose a group of sites : " group

for g in GROUP1 GROUP2 GROUP3; do if [[ $group == $g ]]; then

  # Here's the nameref: After this executes, ARRAY is an alias for
  # the indicated variable.
  declare -n ARRAY=$group
  break

fi

### This is documented but might not work depending on bash version
### Instead you could test for existence of a known key:
###    if [[ ! -v ${ARRAY[SITE1]} ]]; then
if [[ ! -R ARRAY ]]; then
 echo "No such group" >> /dev/stderr; exit 1
fi

OK, you probably don't yet have bash 4.3 but in the future the above will be useful to someone. So without it, you could follow a strategy like the one which you propose, which is to copy the indicated associative array. That's not too bad if the arrays aren't big. To do that, use the above but replace the nameref line (declare -n ARRAY=$group) with the following:

defn=$(declare -p $group)
eval "${defn/$group/ARRAY}"
unset defn

In this case, you'll have the use the alternative test for success.


Note: It's really not a good idea to use all caps for bash variable names. The convention is that system-generated environment variables and shell builtin variables use all caps. User variables should be lower-cased in order to not collide with these predefined variables.

rici
  • 234,347
  • 28
  • 237
  • 341
  • Thanks for your answer rici. I didn't remember to not use caps for user variables. I will try your suggestions tomorrow. – Jaymzwise Sep 10 '14 at 20:48