2016-05-11 11 views
0

Ich versuche, eine Protokolldatei zu öffnen, sie anhand einer Liste von Schlüsselwörtern zu durchsuchen, jede Zeile mit diesem Schlüsselwort zu drucken und die Ergebnisdatei anschließend in ein .gz zu komprimieren.Durchsuchen einer komprimierten Protokolldatei nach einer Liste mit Schlüsselwörtern

Ich habe den folgenden Code erstellt, der ohne Kompilierungsfehler startet. Es schreibt in die Ergebnisdatei, aber wenn ich das Skript ausführe, wird es nie abgeschlossen und findet keine Ergebnisse. Irgendeine Hilfe?

#!/usr/bin/perl 

use IO::Uncompress::Gunzip qw($GunzipError); 
use IO::Compress::Gzip qw(gzip $GzipError) ; 
use diagnostics; 
use strict; 
use warnings; 

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

open(FILE, "</data/bro/scripts/Keywords.txt"); 
my %keywords = map { chomp $_; $_, 1 } <FILE>; 
close(FILE); 

my $logfile = IO::Uncompress::Gunzip->new("/data/bro/logs/2016-05-05/http.00:00:00-06:00:00.log.gz") 
    or die "IO::Uncompress::Gunzip failed: $GunzipError\n"; 

open(FILE, "+>Results.txt"); 
my @results = <FILE>; 

foreach my $line ($logfile) { 
    while (<>) { 
     my @F=split("\t"); 
      next unless ($F[2] =~ /^(199|168|151|162|166|150)/); 

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

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

    my $flag_found = grep {exists $keywords{$_} } split /\s+/, $line; 
    print $line if $flag_found; 
    } 
} 
IO::Compress::Gzip("results.gz") 
      or die "IO::Compress::Gunzip failed: $GzipError\n"; 
close(FILE); 
+2

Im Allgemeinen beinhaltet die 'while (<>)' Zeile eine Tastatureingabe. Vielleicht ist das der Grund, warum Ihr Skript "nie beendet" wird. – red0ct

+0

@ red0ct ist korrekt. Was ist die Absicht der 'while' Schleife? Es möchte, dass du Zeug eingibst. Sie schleifen bereits die Zeilen von '$ logfile' mit der' foreach' (wenn auch nur einmal, weil Sie nichts auf dem :: Gunzip-Objekt aufrufen). – simbabque

+0

Die while-Schleife sollte jede Zeile der Protokolldatei bis zum Ende durchsuchen. Habe ich das falsch gemacht? –

Antwort

3

Wahrscheinlich gibt es keine Notwendigkeit, in while (<>) Schleife in Ihrem Skript, weil diese Linie die Eingabe von der Tastatur verbunden ist.

Das Objekt $logfile von IO::Uncompress::Gunzip->newconstructor zurück können wie normale Dateikennung behandelt werden, so dass Sie nur tun konnte while (<$logfile>) wie:

use IO::Uncompress::Gunzip qw($GunzipError); 
use IO::Compress::Gzip qw(gzip $GzipError) ; 
use strict; 
use warnings; 
use feature 'say'; 

#... 
my @loglines; 

open my $fh, '</data/bro/scripts/Keywords.txt' or die "$!"; 
my %keywords = map { chomp; $_ => 0 } <$fh>; 
close $fh; 

my $logfile = IO::Uncompress::Gunzip->new("...") 
    or die "IO::Uncompress::Gunzip failed: $GunzipError\n"; 

while (<$logfile>) { 
    my @line = split /\t/; 
    next if ! $line[2]; 
    for my $key (keys %keywords) { 
     if ($line[2] =~ /^$key/) { $keywords{$key}++; push @loglines, $_; say; last } 
    } 
} 
# ... pack using gzip 

So ist die @loglines Array alle Zeilen von Protokoll enthält, das eines Ihrer Keywords enthält an der Beginn des dritten ($line[2]) wird durch den '\ t'-Teilstring aufgeteilt. Der Hash-Wert %keywords enthält Schlüsselwörter als Schlüssel und deren Häufigkeit des Auftretens als Werte.


NOTES (Edit): Sie loglines in Hash-speichern kann, wobei jeder Schlüssel ein Schlüsselwort, und jeder Wert sein könnte - ein Array/hash angepaßter Linien (oder Teilketten oder beides). Ich schiebe zum Beispiel einfach passende Linien in ein Array. Sie können es so machen, wie Sie es brauchen, und es dann bequem mit gzip packen.
Auch ist es besser, nicht die globalen Namen wie FILE zu verwenden, weil in einem solchen Fall ein Risiko besteht, anderen Code versehentlich zu verwenden. Überprüfen Sie außerdem, ob Sie das Dateihandle erfolgreich geöffnet haben, z. mit or die wie in Beispiel.

+0

@MichaelMeis bearbeitet. Schauen Sie sich auch [diese] (http://stackoverflow.com/questions/3276674/which-one-is-good-practice-a-lexical-filehandle-or-typeglob) – red0ct

1

IO :: Uncompress :: Gunzip-> Neu gibt ein IO :: Uncompress :: Gunzip Objekt zurück.

foreach my $line ($logfile) { 
    while (<>) { 
     ... 
    } 
} 

macht keinen Sinn, es setzt nur $ Linie auf die IO :: Uncompress :: Gunzip Objekt und wartet dann auf eine Tastatureingabe.

Stattdessen versuchen:

while (my $line = <$logfile>) { 
    ... 
} 

Sie sind auch nicht IO mit Compress :: :: Gzip richtig. Sie können das IO :: Compress :: Gzip-Objekt erstellen, bevor Sie die Protokolldatei verarbeiten und mit dem Ausdruck verwenden. So etwas wie die folgenden funktionieren sollte:

... 
my $z = IO::Compress::Gzip->new("results.gz") 
      or die "IO::Compress::Gunzip failed: $GzipError\n"; 
while (my $line = <$logfile>) { 
    my @F=split("\t", $line); 
     next unless ($F[2] =~ /^(199|168|151|162|166|150)/); 

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

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

    my $flag_found = grep {exists $keywords{$_} } split /\s+/, $line; 
    print $z $line if $flag_found; 
} 

Sie in der Dokumentation für IO :: Uncompress :: Gunzip und IO :: Compress :: Gzip (mit perldoc oder bei cpan.org) aussehen sollte. Es zeigt Beispiele für die korrekte Verwendung dieser Module.

+0

Danke, ich bin immer noch königlich verwirrt, aber ich denke, das hat mich jetzt in die richtige Richtung geleitet. Ich lese mehr auf gzip und erforsche die neuen Fehler, die ich habe. –

Verwandte Themen