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
}
};