我正在编写一个脚本来收集一些不同的网络统计信息。我正在尝试做的是从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 循环后消失了,我不明白为什么。
每当使用管道时,您都会创建一个隐式子外壳。当该子外壳终止时,其变量也会终止。对此的快速解决方法是不要将东西管道输送到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的方法(阅读:更便携,更少bashist)是让一切都发生在子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的wiki上阅读本文(以及更多内容)的细节。
如果您的唯一目标是将命令的输出放入数组(按行),您最好使用内置的(可惜不是很出名)mapfile
bash,它是迄今为止最有效的(也是最适合代码高尔夫的,与其他可能性相比,计算我有多少个字符的笔画):
mapfile -t array < <(netstat -i | tail -n +3)
其他答案解释了为什么你的构造不起作用(管道在子壳中等等)。
help mapfile
该命令的所有详细信息和可能性。
好的,你准备好了吗?
有如何在 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 %12sn" IFace MTU RX TX
IFace MTU RX TX
venet0 1500 0 0
eth1 1500 6400292 6942577
eth0 1500 17647 35426
lo 16436 83 83
不要通过管道连接到循环,bash 首先替换变量,然后在无法访问数组的情况下启动子 shell。
这样做。很好,很简单。
array=()
for alias in `netstat -i | tail -n +3`; do
array+=($alias)
done
echo ${array[@]}