10

I'm trying to loop through an array that contains other arrays and these arrays consist of strings with spaces. The problem is that I can't seem to preserve the spacing in the string. The string with spaces are either divided into multiple items if I change IFS to \n or all the elements of the array are seen as 1 item if I leave IFS unchanged here's some sample code:

#!/bin/sh
low1=("AA  QQ" "BB  LL")
low2=("CC" "DD")
low3=("EE" "FF")
high=(low1 low2 low3)

for high_item in ${high[@]}
do
   eval arrayz=\${$high_item[@]}
   #IFS=$'\n'
   for item in $arrayz
   do
      echo $item
   done
done

Output:

AA
QQ
BB
LL
CC
DD
EE
FF

As you can see the elements "AA QQ" and "BB LL" have been split.

If I uncomment the line that sets IFS to \n I get the following:

AA QQ BB LL
CC DD
EE FF

Now "AA QQ" and "BB LL" are concatenated!

Is there anyway I can preserve these elements just as they original are...I need the output to look like that:

AA QQ
BB LL
CC 
DD
EE 
FF
A K
  • 737
  • 2
  • 8
  • 17
  • For `low1`, you have each element on a separate line. For `low2` and `low3`, all elements appear on a single line. Is this intentional? – chepner Sep 06 '12 at 13:21

2 Answers2

5

I think you meant that the output should look like:

AA  QQ
BB  LL
CC
DD
EE
FF

i.e.:

${low1[0]}
${low1[1]}
${low2[0]}
${low2[1]}
${low3[0]}
${low3[1]}

This could be accomplished using:

#!/bin/bash

low1=("AA  QQ" "BB  LL")
low2=("CC" "DD")
low3=("EE" "FF")
high=(low1 low2 low3)

for high_item in ${high[@]}
do
    x="${high_item}[@]" # -> "low1[@]"
    arrays=( "${!x}" )

    #IFS=$'\n'
    for item in "${arrays[@]}"
    do
        echo "$item"
    done
done

And please always use #!/bin/bash for bash scripts.

Explanation: ${!x} is indirect variable expansion. It evaluates to the value of variable with a name contained in $x.

For our needs, x needs to have the [@] suffix for array expansion as well. Especially note that it is x=${high_item}[@] and not x=${high_item[@]}.

And you have to evaluate it in array context; otherwise, it wouldn't work as expected (if you do arrays=${!x}).

Ah, and as final note: IFS doesn't make any difference here. As long as you are working on quoted arrays, IFS doesn't come into play.

Michał Górny
  • 18,713
  • 5
  • 53
  • 76
4

Replace eval with indirect parameter expansion, and you'll get what I think you want (although it doesn't match your current given output:

for high_item in "${high[@]}"
do
    arrayz="$high_item[@]"
    # arrayz is just a string like "low1[@]"
    for item in "${!arrayz}"
    do
        echo $item
    done
done

Note the need to quote the array expansion in the inner loop to preserve the whitespace in elements of low1.

chepner
  • 497,756
  • 71
  • 530
  • 681