Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array disappear in bash script

Tags:

arrays

bash

I'm writing a script to collect some various network statistics. What I'm trying to do is to produce some delta data from the netstat -i command.

I'm collecting the needed data with the following bash code:

declare -a array
n=0
netstat -i | tail -n +3 | while read LINE; do
        echo "Setting array[$n] to $LINE"
        array[$n]=$LINE
        echo "array now have ${#array[@]} entries"
        let n=$n+1
done
echo "array now have ${#array[@]} entries"

output from this command is:

Setting array[0] to eth0       1500 0   4946794      0      0 0       2522971      0      0      0 BMRU
array now have 1 entries
Setting array[1] to lo        16436 0     25059      0      0 0         25059      0      0      0 LRU
array now have 2 entries
Setting array[2] to vmnet1     1500 0         6      0      0 0          1126      0      0      0 BMRU
array now have 3 entries
Setting array[3] to vmnet8     1500 0       955      0      0 0          1054      0      0      0 BMRU
array now have 4 entries
Setting array[4] to wlan0      1500 0    613879      0      0 0        351194      0      0      0 BMU
array now have 5 entries
array now have 0 entries

As you can see, the array actually disappear after the while loop, and I do not understand why.

like image 487
Dog eat cat world Avatar asked Dec 07 '12 12:12

Dog eat cat world


1 Answers

Any time you use a pipe you create an implicit subshell. When that subshell terminates, so do its variables. A quick fix for this is to not pipe stuff to read. You can accomplish the above using process substitution:

while read LINE; do
        echo "Setting array[$n] to $LINE"
        array[$n]=$LINE
        echo "array now have ${#array[@]} entries"
        let n=$n+1
done < <(netstat -i | tail -n +3)

A more POSIX compliant approach (read: more portable, less bashist) is to make everything happen in the subshell:

netstat -i | tail -n +3 | {
    declare -a array
    n=0
    while read LINE; do
        echo "Setting array[$n] to $LINE"
        array[$n]=$LINE
        echo "array now have ${#array[@]} entries"
        let n=$n+1
    done
    echo "array now have ${#array[@]} entries"
}

You can read the fine points of this (and more) at Greg Wooledge's wiki.

like image 155
kojiro Avatar answered Sep 27 '22 20:09

kojiro