Referencing bash array variables from another array

Bash 4.3 and later supports "name references", or namerefs (a similar concept exists in ksh93, but the scoping is annoyingly different):

#!/bin/bash

array1=('array1string1' 'array1string2')
array2=('array2string1' 'array2string2')

array_names=('array1' 'array2')

for a in "${array_names[@]}"; do
    declare -n arr="$a"

    for b in "${arr[@]}"; do
        echo "$b"
    done
done

The variable arr is a nameref that acts like an alias for the named variable (the variable with name $a in this example).

Without namerefs, in earlier Bash versions, one solution would be to create a new array that contains all the elements from the other arrays:

all=( "${array1[@]}" "${array2[@]}" )

... a bit like the array_names array in the question but with the contents of all arrays, and then iterate over "${all[@]}".

It's also possible to use eval, but the resulting code looks astoundingly awful.

See glenn jackman's answer for a variation with variable indirection (introduced in its current form with Bash version 2).


@Kusalananda has the best answer for recent versions of bash. For earlier versions, you can use an indirect variable:

for a in ${array_names[@]}; do 
    tmp="${a}[@]"
    for b in "${!tmp}"; do echo "$b"; done     # or: printf "%s\n" "${!tmp}"
done

See the 4th paragraph of https://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion