Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loop through array of arrays of string with spaces

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
like image 819
A K Avatar asked Sep 06 '12 12:09

A K


Video Answer


2 Answers

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.

like image 138
Michał Górny Avatar answered Oct 26 '22 06:10

Michał Górny


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.

like image 37
chepner Avatar answered Oct 26 '22 06:10

chepner