0

I'd like to use arrays in BASH properly when using indirection ${!varname}.

Here's my sample script:

#!/bin/bash
i="1 2 3"
x=CONFIG
y1=( "A and B" "B and C" )
# y1=( "\"A and B\"" "\"B and C\"" )
y2=( "ABC and D" )
y3=

echo "y1=${y1[@]}"
echo "y2=${y2[@]}"
echo "y3=${y3[@]}"
echo "==="

for z in $i
do
    t=y${z}
    tval=( ${!t} )
    r=0
    echo "There are ${#tval[@]} elements in ${t}."
    if [ ${#tval[@]} -gt 0 ]; then
        r=1
        echo "config_y${z}=\""
    fi
    for tv in "${tval[@]}"
    do
        [ -n "${tv}" ] && echo "${tv}"
    done
    if [ "x$r" == "x1" ]; then
        echo "\""
    fi
done

Here's the result:

y1=A and B B and C
y2=ABC and D
y3=
===
There are 3 elements in y1.
config_y1="
A
and
B
"
There are 3 elements in y2.
config_y2="
ABC
and
D
"
There are 0 elements in y3.

What I would like to get instead is:

y1=A and B B and C
y2=ABC and D
y3=
===
There are 2 elements in y1.
config_y1="
A and B
B and C
"
There are 1 elements in y2.
config_y2="
ABC and D
"
There are 0 elements in y3.

I also tried to run something like this:

#!/bin/bash
i="1 2 3"
x=CONFIG
y1=( "A and B" "B and C" )
# y1=( "\"A and B\"" "\"B and C\"" )
y2=( "ABC and D" )
y3=
for variable in ${!y@}
do
  echo "$variable"        # This is the content of $variable
  echo "${variable[@]}"   # So is this
  echo "${!variable}"     # This shows first element of the indexed array
  echo "${!variable[@]}"  # Not what I wanted
  echo "${!variable[0]} ${!variable[1]}"  # Not what I wanted
  echo "---"
done

Ideally, ${!Variable[@]} should do what I want, but it doesn't. Also, ${!Variable} only shows the first element of the array,

What can I try?

tripleee
  • 175,061
  • 34
  • 275
  • 318
user1936810
  • 71
  • 2
  • 7

1 Answers1

0

Your syntax for accessing arrays is wrong here:

tval=( ${!t} )

This will evaluate to e.g. $y1 but you want "${y1[@]}" which is how you address an array with that name with proper quoting.

Unfortunately, there is no straightforward way to refer to an array through indirection, but see Indirect reference to array values in bash for a couple of workarounds.

Notice also how

y3=()

is different from

y3=

Using variables for stuff which isn't actually variable is a bit of a code smell, too.

#!/bin/bash
i="1 2 3"
x=CONFIG
y1=( "A and B" "B and C" )
y2=( "ABC and D" )
# Fix y3 assignment
y3=()

echo "y1=${y1[@]}"
echo "y2=${y2[@]}"
echo "y3=${y3[@]}"
echo "==="

for z in $i
do
    # Add [@] as in Aaron's answer to the linked question
    t=y${z}[@]
    # And (always!) quote the variable interpolation
    tval=( "${!t}" )
    r=0
    echo "There are ${#tval[@]} elements in ${t}."
    if [ ${#tval[@]} -gt 0 ]; then
        r=1
        echo "config_y${z}=\""
    fi
    for tv in "${tval[@]}"
    do
        [ -n "${tv}" ] && echo "${tv}"
    done
    if [ "x$r" = "x1" ]; then
        echo "\""
    fi
done

Probably also investigate printf for unambiguously printing values.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • As you can see, code in comments doesn't really work. You can use another gratuitous variable if you like, of course, but I would advise against using upper case for your private variables. – tripleee Nov 26 '19 at 10:56