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

但无法弄清楚如何打印出二维数组的元素及其值。似乎沿着这条线的东西会处理唯一的目标端口任务,因为每个端口都在覆盖元素的值。

注意: 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 的一种方法:

 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 回答