问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/25767413/bash-use-a-variable-as-an-associative-array-name