如何根据出现次数限制打印输出 (AWK)

如何根据出现次数限制打印输出 (AWK)

所以我试图通过 https 来追踪在我们的网络上浏览色情内容的人。该模式很容易看出,在我们的 Bro 日志的 HTTP 标头中,连续 15 个以上的图像点击量没有引用网址。

Bro 中的相关列是 $3 = 主机 IP、$11 = 引用者、$14 = 文件大小和 $27 = mime 类型。

因此,我目前正在使用...

awk -F "\t" '$11 ~ /^\-$/ && $14 > 100000 && $27 ~ /^image/'

我想做的是知道是否有一种方法,仍然在单行命令中运行一个子命令,告诉 awk 仅打印 $3 中的 IP 出现 >= 15 次的行。

我的猜测是我必须创建一个 awk 程序来执行类似的操作。我希望这里有一个高手可以帮助我避免这种情况。我不反对使用另一个正则表达式命令,如果它能更好地工作的话(perl、grep、egrep、agrep、bro-cut)。

更新:解释这一点的最佳方式是通过 Excel 术语。awk 是否有类似 countif Excel 函数的功能?=countif(C1,C:C)>15

样本日志:

1443534069  CGAdXyZgN3wVwihi6   123.456.789.012 59713   93.184.216.98   80  1   GET 40.media.tumblr.com /1fbe50fff7a17f84acdc30b03d9b6335/tumblr_nvf1dfH8oz1tco00do1_500.jpg    -   Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.99 Safari/537.36    0   89522   200 OK  -   -   -   (empty) -   -   -   -   -   FIGAv51OT15ak4eDCl  image/jpeg
1443534069  CkST1DjXDkCBDYhYa   123.456.789.012 59712   93.184.216.98   80  1   GET 40.media.tumblr.com /e8f958e0dcd3eb419035a8d3271d07e8/tumblr_npr5drTCOO1qk489oo1_500.jpg    -   Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.99 Safari/537.36    0   83743   200 OK  -   -   -   (empty) -   -   -   -   -   FWRWZX2XgQQqfm9OMe  image/jpeg
1443534069  C8GvXwqAiR84PGGkk   123.456.789.012 59714   93.184.216.98   80  1   GET 40.media.tumblr.com /0b80deef543f6da28b48db0578fb3bd4/tumblr_n0chjkQICf1qeu577o1_500.jpg    -   Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.99 Safari/537.36    0   70530   200 OK  -   -   -   (empty) -   -   -   -   -   FOHdJ62uCU30UE9VYg  image/jpeg
1443534069  CMXgz73HlqL5Z0WVR7  123.456.789.012 59715   54.230.193.223  80  1   GET 36.media.tumblr.com /547822945f762adb310bb966c1f9c886/tumblr_nv3xgebHVH1sbsr1vo1_500.jpg    -   Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.99 Safari/537.36    0   67589   200 OK  -   -   -   (empty) -   -   -   -   -   FmaN4d2eimhA2CpEmd  image/jpeg

答案1

此 perl 脚本将符合条件(“image/”,> 100000 字节,referrer = '-')的每个日志行存储在由 IP 地址作为键控的数组哈希中。在脚本末尾,它打印出每个包含超过 14 个条目的 IP 地址的每个数组行。

它使用大量内存,但不如存储每个输入行那么多。

您可以将其压缩为一行,但您只会无缘无故地使其不可读/不可调试。

#! /usr/bin/perl

use strict;

my %LOGLINES = ();

while (<>) {
    next unless (/\bimage\//);
    my @F=split("\t");
    next unless ($F[10] eq '-');
    next unless ($F[13] > 100000);

    push @{ $LOGLINES{$F[2]} }, $_;
};  

foreach my $key (sort keys %LOGLINES) {
   print @{ $LOGLINES{$key} } if (scalar @{ $LOGLINES{$key} } > 14);
}  

请注意,perl 数组是从 0 开始的,而不是从 1 开始的。因此字段编号与您指定的字段编号偏移 -1。

这是另一个版本,它不使用尽可能多的内存,因为它只为它看到的每个 IP 地址存储最多 15 行,然后它开始打印它看到的匹配行。缺点是输出不按 IP 地址排序,但这可以通过管道到sort -t $'\t' -k2.

#! /usr/bin/perl

use strict;

my %LOGLINES = ();
my %count = ();

while (<>) {
    next unless (/\bimage\//);
    my @F=split("\t");
    next unless ($F[10] eq '-');
    next unless ($F[13] > 12000);

    $count{ $F[2] }++;

    if ($count{ $F[2] } == 15) {
      print @{ $LOGLINES{$F[2]} };   # print all the log lines we've seen so far
      print $_;                      # print the current line
    } elsif ($count{ $F[2] } > 15) {
      print $_;                      # print the current line
    } else {
      push @{ $LOGLINES{$F[2]} }, $_; # store the log line for later use
    }
};

相关内容