1

I have a log file ala.txt looking like that:

dummy FromEndPoint = PW | dummy | ToEndPoint = LALA | dummy
dummy FromEndPoint = PW | dummy | ToEndPoint = PAPA | dummy
dummy FromEndPoint = WF | dummy | ToEndPoint = LALA | dummy
dummy FromEndPoint = WF | dummy | ToEndPoint = KAKA | dummy

I used sed to generate an array containing every combination of FromEndPoint and ToEndPoint. Then I want to iterate through it.

function main {
    file="./ala.txt"
    local a=`sed 's/^.*FromEndPoint = \([a-zA-Z\-]*\).*ToEndPoint = \([a-zA-Z\-]*\).*$/\1;\2/' $file | sort -u`

    echo ${#a[@]} # prints 1

    for connectivity in ${a[@]}; do
        echo "conn: $connectivity" # iterates 4 times
        #conn: PW;LALA
        #conn: PW;PAPA
        #conn: WF;KAKA
        #conn: WF;LALA
    done

}

Why echo ${#a[@]} prints 1 if there are 4 elements in the array? How can I get a real size of it?

Bash used: 4.4.12(1)-release

Inian
  • 80,270
  • 14
  • 142
  • 161
aerion
  • 702
  • 1
  • 11
  • 28
  • `local a=\`cmd\`` is not a declaration of an array. `a` is just a string. It then undergoes word-splitting in the `for` loop resulting in 4 iterations. – PesaThe Apr 10 '18 at 13:49
  • `local -a a` and `local -A a` don't work neither. – aerion Apr 10 '18 at 13:51
  • 1
    `declare -p a` will show its definition. That will show you that it contains only one element, with spaces in it; *not* each space-separated piece in a different element. – Charles Duffy Apr 10 '18 at 13:54
  • Quoting your expansion, as in `for connectivity in "${a[@]}"; do`, would iterate one array element per run of the loop, not splitting on spaces (and expanding globs), and so would make the number of times your loop iterates consistent with the number of elements in your array. – Charles Duffy Apr 10 '18 at 13:55

1 Answers1

2

Don't use variables to store multi-line content, use arrays!

In a bash shell you could process substitution feature to make the command output appear as a file content for you to parse over with an array. in bash versions of 4 and above, commands readarray and mapfile can parse the multi-line output given a delimiter without needing to use a for-loop with read

#!/usr/bin/env bash

array=()
while read -r unique; do
    array+=( "$unique" )
done< <(sed 's/^.*FromEndPoint = \([a-zA-Z\-]*\).*ToEndPoint = \([a-zA-Z\-]*\).*$/\1;\2/' file | sort -u)

Now printing the length of the array as echo "${#array[@]}" should print the length as expected.

And always separate the initialization of local variables and assigning of the values to it. See Why does local sweep the return code of a command?

Inian
  • 80,270
  • 14
  • 142
  • 161