数组在bash脚本中消失

时间:2012-12-07 12:36:58

标签: arrays bash

我正在编写一个脚本来收集各种网络统计信息。 我要做的是从netstat -i命令生成一些增量数据。

我正在使用以下bash代码收集所需数据:

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"

此命令的输出是:

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

正如您所看到的,数组实际上在while循环后消失了,我不明白为什么。

3 个答案:

答案 0 :(得分:5)

每次使用管道时,都会创建一个隐式子shell。当子shell终止时,它的变量也会终止。对此的快速解决方法是不将内容传递给read。您可以使用流程替换来完成上述操作:

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)

更符合POSIX标准的方法(阅读:更便携,更少基础)是让所有事情都在子shell中发生:

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"
}

您可以在Greg Wooledge's wiki上阅读此内容(以及更多内容)。

答案 1 :(得分:2)

如果您的唯一目标是将命令的输出放入数组(行方向),那么最好使用(遗憾的是不是很知名的)mapfile bash内置,它是迄今为止效率最高的(最适合代码高尔夫,计算我与其他可能性相比的字符笔划数):

mapfile -t array < <(netstat -i | tail -n +3)

其他答案解释了为什么你的构造不起作用(管道在子壳中,所有这些)。

help mapfile了解该命令的所有细节和可能性。

答案 2 :(得分:1)

好的,你准备好了吗?

如何在 bash 数组关联数组中转换netstat -i | tail -n +3

declare -A AANET
while read -a line ;do
    declare -a AI$line
    eval "AI$line=(${line[@]})"
    AANET[$line]=AI$line
  done < <(
    netstat -i |
       tail -n +3)

比现在:

echo ${!AANET[@]}
venet0 eth1 eth0 lo br0

echo ${AANET[eth0]}
AIeth0

对于子关联,我们必须使用eval

eval echo \${${AANET[eth0]}[@]}
eth0 1500 0 17647 0 0 0 35426 0 0 0 BMPU

eval echo \${${AANET[eth0]}[1]}
1500

eval echo \${${AANET[eth0]}[3]}
17647

eval echo \${${AANET[eth0]}[7]}
35426

eval echo \${${AANET[eth0]}[@]:3:5}
17647 0 0 0 35426

用于分配临时变量:

eval currentBin=\${${AANET[eth0]}[3]} currentBout=\${${AANET[eth0]}[7]}
echo $currentBout 
35426
echo $currentBin 
17647

甚至是:

eval "declare -a currentVals=(\${${AANET[eth0]}[@]:3:8})"
echo ${currentVals[0]}
17647
echo ${currentVals[4]}
35426
echo ${currentVals[@]}
17647 0 0 0 35426 0 0 0

修改

好的,如果可能没有 eval

for aKey in ${!AANET[@]};do
    fields=(${AANET[$aKey]}{[1],[3],[7]});
    echo $aKey ${!fields} ${!fields[1]} ${!fields[2]}
  done |
    xargs printf "%-9s %12s %12s %12s\n" IFace MTU RX TX

IFace              MTU           RX           TX
venet0            1500            0            0
eth1              1500      6400292      6942577
eth0              1500        17647        35426
lo               16436           83           83