calling other variables in a variable name (Bash)

langs is not an array but a string in your code.

To make it an array and use it:

langs=( EN GE )

for i in "${langs[@]}"; do
    declare -n p="dir_$i"
    dir_ml+=( "$p" )

printf 'dir_ml = "%s"\n' "${dir_ml[@]}"

In the above loop, $i will take the values EN and GE in turn. This also introduces a name reference variable p. When the value of p is accessed, the string that was assigned to the variable when it was declared will be interpreted as a variable name and that variable's value is returned.

The output of the above will be

dir_ml = "/xx"
dir_ml = "/zz"

To use name references in bash, you will need bash version 4.3 or later.

Another (interesting but inferior) possibility:


# (can't set dir_ml=() here as its name would be picked up by the loop)
unset dir_ml

for i in "${!dir_@}"; do
    dir_ml+=( "${!i}" )

printf 'dir_ml = "%s"\n' "${dir_ml[@]}"

Here, $i will take the values of the variable names dir_EN and dir_GE in turn. We then use variable indirection with ${!i} to get the value of that variable. This variation does not need the langs array, but it instead assumes that no other variable is named dir_-something (which may be considered a bit fragile as a user may easily inject variables with names like these into the script's environment).

The output is the same for this code as for the code above.

This can be accomplished as follows:

langs=(EN GE)

for i in ${!langs[@]}; do

First I have changed langs="EN GE" to langs=(EN GE) because this needs to be an array.

I have also changed $(seq 0 1) to ${!langs[@]} which will expand to the index (or name in the case of an associative array) of each item in the array. So in this example 0 1.

Then I set a temp variable to dir_${langs[i]} (dir_EN and dir_GE).

Then using the ! parameter expansion I expand the variable with that name to set the element of dir_ML