使用Perl在大日志文件中读取和存储某些值的快速方法

时间:2013-05-28 05:16:10

标签: perl search logging

很抱歉问了很多次关于阅读线和其他东西的问题。我碰巧正在处理这样一个巨大的(500,000行)文件:

2013-05-27T19:01:23 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:29 [INFO] item_id:2, pause at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23

我需要做的是,在文件位置作为输入的情况下,创建一个输出类似于以下内容的脚本:

$output = [ {item_id => 1, counter => 2 }, { item_id...... 

也就是说,每个item_id应该与数组ref中的启动次数配对。请注意,我不能使用“while”多次读取文件,因为它太大了。另外,我不知道有多少项目。

我使用Stackoverflow成员提示编写的方法如下:

sub count_start{
open LOGFILE, $file_location;
my $max;
my $i;
my $counter = 0;
my $found = 0;
my $data;

while (<LOGFILE>) {
  next unless /item_id:(\d+)/;
  $found = $1 if $found < $1;

  for ($i =1, $i<=$found, $i++){
   if ($file_location =~ /\bitem_id:$i, start\b/ig){
   $counter++;
   }
  $output = [ $i => $counter ];
  } 
}
close LOGFILE;
return $output;
}
1;

但是一切都变得非常错误:(。我收到了很多令人讨厌的警告,没有任何类似于我的要求。任何想法或建议?

原谅这个perl新手,因为他糟糕的代码。

2 个答案:

答案 0 :(得分:1)

您不能在列表中添加类似哈希的关联。为此你需要一个哈希:

use strict;
use warnings;
my %output;
my $filename = shift @ARGV;
open my $file, "<", $filename or die("$!: $filename");
while (<$file>) {
    if (/item_id:(\d+)\s*,\s*start/) {
        $output{$1}++;
    }
}
close $file;
for my $item(keys %output) {
    print "$item -> $output{$item}\n";
}

<强>输出

1 -> 5
3 -> 3
5 -> 4

您可以使用以下方法替换while循环:

/item_id:(\d+)\s*,\s*start/ and $output{$1}++ while <$file>;

但它不是真的可读。

答案 1 :(得分:1)

我会使用哈希来进行计数,然后将其转换为哈希数组。但是,看起来您使用perl代码来存储数据,这不是最好的主意。有更好的格式,例如JSON,甚至Text::CSV

除此之外,Data::Dumper模块可用于此目的。

use strict;
use warnings;
use Data::Dumper;

my %output;

while (<DATA>) {
    if (/ item_id:(\d+), start at /) {
        $output{$1}++;
    }
}

my @data = map { { item_id => $_, counter => $output{$_} } } keys %output;
print Dumper \@data;


__DATA__
2013-05-27T19:01:23 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:29 [INFO] item_id:2, pause at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:1, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:3, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23
2013-05-27T19:01:30 [INFO] item_id:5, start at Reader.pm line 23

<强>输出:

$VAR1 = [
          {
            'counter' => 5,
            'item_id' => '1'
          },
          {
            'counter' => 3,
            'item_id' => '3'
          },
          {
            'counter' => 5,
            'item_id' => '5'
          }
        ];

请注意,由于散列未排序,输出未排序。如果要对其进行排序,可以将sort功能应用于键。

另请注意,此版本考虑到您说要计算“开始”,其中此输入不包括显示item_id:2, pause at的第2行。