Como limitar a saída impressa com base no número de ocorrências (AWK)

2

Por isso, estou tentando rastrear pessoas em nossa rede de navegação pornográfica via https. O padrão é bem fácil de ver, com mais de 15 acessos seguidos para imagens sem um referenciador no cabeçalho HTTP em nossos registros do Bro.

As colunas relevantes no Bro são $ 3 = IP do host, $ 11 = referenciador, $ 14 = tamanho do arquivo e $ 27 = tipo mime.

Assim, estou usando atualmente ...

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

O que eu gostaria de fazer é saber se existe uma maneira, ainda dentro do comando de linha única, de executar um subcomando que diga ao awk para imprimir apenas as linhas onde o IP em $ 3 ocorre > = 15 vezes.

Meu palpite é que terei que criar um programa awk para fazer algo assim. Espero que haja um gênio aqui que possa me ajudar a evitar isso. Não me oponho a usar outro comando regex se ele funcionasse melhor (perl, grep, egrep, agrep, bro-cut).

Atualização: A melhor maneira de explicar isso seria via termos do Excel. O awk tem algo parecido com a função do Excel? = countif (C1, C: C) > 15

Log de amostra:

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
    
por user112802 07.10.2015 / 03:37

1 resposta

2

Este script perl armazena cada linha de registro que corresponde aos critérios (uma "imagem /", > 100000 bytes, referenciador = '-') em um Hash of Arrays codificado pelo endereço IP. No final do script, ele imprime todas as linhas da matriz para cada endereço IP que tenha > 14 entradas.

Ele usa muita memória, mas não tanta memória quanto se armazenasse todas as linhas de entrada.

Você pode condensá-lo em uma linha única, mas estaria apenas tornando-a ilegível / não-depurável sem um bom motivo.

#! /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);
}  

Observe que os arrays perl são baseados em zero, não em 1. assim, os números de campo são compensados por -1 do que você especificou.

Aqui está outra versão que não usa nem de perto o máximo de memória, pois armazena apenas até 15 linhas para cada endereço IP que vê, então começa a imprimir as linhas correspondentes como elas são exibidas. A desvantagem é que a saída não é classificada por endereço IP, mas isso é facilmente resolvido pela canalização para 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
    }
};
    
por 07.10.2015 / 04:55

Tags