根据关键字列表搜索压缩日志文件

时间:2016-05-11 06:01:00

标签: perl grep

我正在尝试打开日志文件,针对关键字列表进行搜索,打印包含该关键字的每一行,然后将结果文件压缩为.gz。

我已经提出了下面的代码,它开始运行时没有编译错误。它写入结果文件,但是当我运行脚本时它永远不会完成,它永远不会找到任何结果。有什么帮助吗?

    #!/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 个答案:

答案 0 :(得分:3)

你的脚本中可能没有while (<>)循环,因为这一行涉及键盘的输入。

$logfile constructor返回的对象IO::Uncompress::Gunzip->new可以像普通的文件句柄一样处理,因此你可以像while (<$logfile>)那样:

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

因此,@loglines数组包含来自日志的所有行,其中包含您在第三个($line[2])开始时的一个关键字,由&#39; \ t&#39;子。 %keywords哈希包含关键字作为键及其出现频率作为值。

注意(编辑):您可以以散列形式存储日志,其中每个键可以是关键字和每个值 - 匹配行(或子串或两者)的数组/散列。我只是将匹配的行推入数组中。您可以根据需要进行操作,然后以方便的方式使用gzip打包 另外,最好不要使用像FILE这样的全局名称,因为在这种情况下,有其他代码偶然使用它的风险。除了验证您是否已成功打开文件句柄,例如例如or die

答案 1 :(得分:1)

IO :: Uncompress :: Gunzip-&gt; new返回一个IO :: Uncompress :: Gunzip对象。

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

毫无意义,它只是将$ line设置为IO :: Uncompress :: Gunzip对象,然后等待键盘输入。

而是尝试:

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

您也没有正确使用IO :: Compress :: Gzip。您可以在处理日志文件之前创建IO :: Compress :: Gzip对象,并将其与print一起使用。以下内容应该有效:

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

您应该查看IO :: Uncompress :: Gunzip和IO :: Compress :: Gzip的文档(使用perldoc或cpan.org)。它显示了正确使用这些模块的示例。