5

さまざまなネットワーク統計を収集するスクリプトを作成しています。私がやろうとしているのは、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 ループの後で実際に消えてしまいますが、その理由はわかりません。

4

3 に答える 3

5

パイプを使用するときはいつでも、暗黙的なサブシェルを作成します。そのサブシェルが終了すると、その変数も終了します。これを簡単に解決するには、 にパイプを入れないこと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 準拠のアプローチ (より移植性が高く、バシストが少ない) は、サブシェルですべてを実行することです。

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で、これ (およびその他) の細かい点を読むことができます。

于 2012-12-07T12:47:50.343 に答える
2

コマンドの出力を (行ごとに) 配列に入れることが唯一の目的である場合は、(残念ながらあまり知られていない) mapfilebash 組み込み関数を使用することをお勧めします。これは、はるかに効率的であり、コード ゴルフに最適です。 、他の可能性と比較して、私が持っている文字ストロークの数を数えます):

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

他の答えは、あなたの構造がうまくいかなかった理由を説明しています(パイプはサブシェルにあり、そのすべてです)。

help mapfileそのコマンドのすべての詳細と可能性について。

于 2012-12-07T14:33:09.023 に答える
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

編集

OK、それがなく 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
于 2012-12-07T13:55:06.790 に答える