1

演習として awk で問題を解決しようとしていますが、問題が発生しています。awk (または gawk) が、特定の送信元 IP アドレスの一意の宛先ポートをすべて出力できるようにしたいと考えています。

ソース IP アドレスはフィールド 1 ($1) で、宛先ポートはフィールド 4 ($4) です。

Cut for brevity:
SourceIP          SrcPort   DstIP           DstPort
192.168.1.195       59508   98.129.121.199  80
192.168.1.87        64802   192.168.1.2     53
10.1.1.1            41170   199.253.249.63  53
10.1.1.1            62281   204.14.233.9    443

各ソース IP を配列へのインデックスとして保存すると思います。しかし、宛先ポートを値として保存する方法がよくわかりません。おそらく、文字列に追加し続けることができます。これは、インデックスの値です。たとえば、「80」、「80,443」など、一致ごとに。しかし、それは最善の解決策ではないかもしれません。

私は出力についてあまり心配していません。本当に awk でこれにどのようにアプローチできるかを知りたいだけです。とはいえ、出力については、次のようなことを考えていましたが、

Source IP:dstport, dstport, dstport
192.168.1.195:80,443,8088,5900

こんなものをいじっていますが、

awk '{ if ( NR == 1) next; arr[$1,$4] = $4 } END { for (i in arr) print arr[i] }' infile

しかし、2 次元配列の要素とその値を出力する方法がわかりません。各ポートが要素の値を上書きしているため、この行に沿った何かが一意の宛先ポートタスクを処理するようです。

注: awk/gawkソリューションで答えが得られます!

ソリューションの編集:私の質問で述べたように一意の宛先ポートを出力し、列のヘッダー行をスキップするようにケントのソリューションをわずかに変更しました。

awk '{ if ( NR == 1 ) next ; if ( a[$1] && a[$1] !~ $4 ) a[$1] = a[$1]","$4; else a[$1] = $4 } END {for(x in a)print x":"a[x]}'
4

2 に答える 2

2

ここに awk の 1 つの方法があります。

 awk '{k=$1;a[k]=a[k]?a[k]","$4:$4}END{for(x in a)print x":"a[x]}' file

あなたの例では、出力は次のとおりです。

kent$  awk '{k=$1;a[k]=a[k]?a[k]","$4:$4}END{for(x in a)print x":"a[x]}' file                                                                                               
192.168.1.195:80
192.168.1.87:53
10.1.1.1:53,443

(タイトル行は省略しました)

編集

k=$1;a[k]=a[k]?a[k]","$4:$4

は次とまったく同じです:

if (a[$1])                   # if a[$1] is not empty
    a[$1] = a[$1]","$4       # concatenate $4 to it separated by ","
else                         # else if a[$1] is empty
    a[$1] = $4               # let a[$1]=$4

k=$1入力を節約するためだけに使用しました。x=boolean?a:b表現も

説明がコードを理解するのに役立つことを願っています。

于 2013-05-24T21:29:20.900 に答える
1

perl配列のハッシュのようなデータ構造を作成する可能性がもっと好きなので、使用するソリューションを好みます。

perl -ane '
    ## Same BEGIN block than AWK. It prints header before processing any input.
    BEGIN { printf qq|%s:%s\n|, q|Source IP|, q|dstport| }

    ## Skip first input line (header).
    next if $. == 1;

    ## This is what you were thinking to achieve. Store source IP as key of a 
    ## hash, and instead of save a string, it will save an array with all
    ## ports.
    push @{ $ip{ $F[0] } }, $F[ 3 ]; 

    ## Same END block than AWK. For each IP, get all ports saved in the array
    ## and join them using a comma.
    END { printf qq|%s:%s\n|, $_, join q|,|, @{ $ip{ $_ } } for keys %ip }

' infile

次の結果が得られます。

Source IP:dstport
192.168.1.195:80
10.1.1.1:53,443
192.168.1.87:53
于 2013-05-24T20:39:11.687 に答える