2012-12-07 32 views
4

我正在編寫一個腳本來收集一些各種網絡統計信息。 我想要做的是從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循環後消失

我用下面的bash代碼收集所需數據,我不明白爲什麼。

回答

4

任何時候您使用管道創建隱式子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標準的方法(閱讀:更輕便,少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's wiki

+0

謝謝,第一個代碼完美工作。但數組在子外殼之外丟失。我懷疑這是意圖,但不適合我。 –

+0

非常好。我更喜歡符合POSIX的方法,因爲它在開始時提供輸入數據,支持按時間順序排列的閱讀。 – Arthur

+1

@Arthur你可以在開始時提供輸入數據。讀取LINE時,<<<(netstat ...);做......' – kojiro

1

好的,你準備好了嗎?

還有就是如何在陣列的慶典關聯數組轉換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 

一種用於assing一個臨時變量:

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 
+0

對於我來說''eval'太多':-('。Bash從來沒有爲這種東西設計過,如果你真的需要這些構造,只需使用另一種語言。 –

+0

@gniourf_gniourf你是從* php *來的嗎?在這種情況下,你可以使用'eval'來確定哪種數據可以被評估*在這種情況下,命令'netstat -i'不會返回反碼或者這樣的*跨腳本* echapments。 –

+0

不是,不是隻是我知道什麼語言適合於什麼任務(或者至少,我相信我是這樣做的) –

2

如果你唯一的目標是把一個命令的輸出到一個數組(面向行),你最好使用(可惜不是很出名)mapfile bash的內置,這是迄今爲止最有效的(和最適合的代碼高爾夫,算我有多少字符筆劃相對於其他的可能性):

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

其他的答案解釋爲什麼你的結構不工作(管道是在子shell和所有)。

help mapfile瞭解該命令的所有細節和可能性。