Perl - 在两个时间戳之间读取文件

时间:2014-05-05 20:11:10

标签: perl parsing time timestamp

我有一个日志文件,我希望按照时间戳读取块(5分钟数据,一次一个)。样品是

2014/04/24-23:29:20.003078-<String>
2014/04/24-23:29:32.003157-<String>
2014/04/24-23:29:33.004872-<String>
2014/04/24-23:29:43.005785-<String>

现在我打开文件并使用触发器操作来查看行时间戳是否在5分钟之间。 (我将从2014/04 / 24-00:00:00到2014/04 / 24-00:05:00开始第一块)。但是触发器没有返回。我将DATE字符串作为参数(如scr.pl 04/24/2014)。我的代码是:

$curr = timelocal(0, 0, 0, (split /\//, $ARGV[0])[1], (split /\//, $ARGV[0])[0]-1, (split /\//, $ARGV[0])[-1]);
$currentTime = strftime "%Y/%m/%d-%H:%M:%S", localtime($curr); 
$curr += 300;
$nextTime = strftime "%Y/%m/%d-%H:%M:%S", localtime($curr);

    $file='Output.txt';
    open(INFO, $file) or die("Could not open  file.");
    foreach $line (<INFO>)  {
            print "$currentTime\n\n$nextTime";
            if (/$currentTime/../$nextTime/){
            $dataChunk = "$dataChunk\n$line"; #nothing gets added to $dataChunk
        }else{
              <DO SOME STUFF on DATACHUNK above>
            }
          }
     close(<INFO>);

为什么没有任何回报的想法?


我现在正在使用以下代码。它起作用了,但它再次慢到我的期望。

$currentTime = timelocal(0, 0, 0, (split /\//, $ARGV[0])[1], (split /\//, $ARGV[0])[0]-1, (split /\//, $ARGV[0])[-1]);
$nextTime = $currentTime + 300;
            my $date = substr($line1,0,19); #2014/04/24-23:29:21
            my ($year,$mon,$mday,$hour,$min,$sec) = split(/[\s\/\-:]+/, $date); 
            my $time = timelocal($sec,$min,$hour,$mday,$mon-1,$year);
            if ($currentTime <= $time && $nextTime > $time)

3 个答案:

答案 0 :(得分:0)

关于使用触发器操作员的个人偏好是我看到的一些事情。

  1. 您在触发器范围内的正则表达式使用隐式$_循环变量,但您已明确告知foreach循环使用$line代替。由于$_中没有任何内容,您的触发器将始终返回false。

  2. 你使用带有正则表达式的触发器意味着它只有在发现行具有您正在寻找的确切时间时才会开始和停止返回true。您的输入参数$ARGV[0]不允许您指定时间,仅指定日期。您可以获得的最接近的是通过&#34; 04/24/2014&#34;这将产生$currentTime == '2014/04/24-00:00:00'$nextTime == '2014/04/24-00:05:00'。这些时间不匹配示例输入中的任何行。您的更新使用了<=>=,但它仍然可以使用触发器操作符。这就是它的设计目的。

  3. 还有更多问题,所以通过在代码顶部添加以下内容来启用严格模式和警告:

    use strict;
    use warnings;
    

    完成此操作后,您会看到一堆语法错误和警告。他们应该引导你朝着正确的方向前进。然后,调试并针对您遇到的每个问题分别提出问题

答案 1 :(得分:0)

使用Time::PieceTime::Seconds来处理时间戳。与原始解析相比,它更清晰,更易于使用。此外,它使您的输出更灵活。

我永远无法让翻转/翻牌操作员做我想做的事。只需使用带有时间范围的if语句。

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw(say);
use autodie;

use Time::Seconds;
use Time::Piece;

use constant {
    START_TIME          => "2014/04/24-23:25:29",
    TIME_PERIOD         => 5,
    TIME_FORMAT         => "%Y/%m/%d-%H:%M:%S",
};

my $start_time = Time::Piece->strptime( START_TIME, TIME_FORMAT );
my $end_time   = $start_time + ( ONE_MINUTE * TIME_PERIOD );

while ( my $line = <DATA> ) {
    chomp $line;
    my $time_string = $line;
    $time_string =~ s/\..*//;
    my $time = Time::Piece->strptime( $time_string, TIME_FORMAT );
    if ( $time->epoch >= $start_time->epoch
            and $time->epoch <= $end_time->epoch ) {
        say "$line";
    }
}

__DATA__
2014/04/24-23:29:20.003078-<String>
2014/04/24-23:29:32.003157-<String>
2014/04/24-23:29:33.004872-<String>
2014/04/24-23:29:43.005785-<String>
2014/04/24-23:30:43.005785-<String>
2014/04/24-23:31:43.005785-<String>

答案 2 :(得分:-1)

我不确定你认为// .. //会做什么,但我向你保证,这不是你想要的。

//包含正则表达式,..是范围运算符。这意味着你的if语句正在执行此操作:

$_/$currentTime/的正则表达式进行比较,并将其与/$nextTime/的重复数据进行比较,然后根据范围运算符的标量上下文使用返回布尔值:

  

只要左操作数为false,它就是false。一旦左操作数为真,范围运算符将保持为真,直到右操作数为真,此后范围运算符再次变为假。

在您的情况下,这意味着它实际上总是返回false,因此条件永远不会执行。

您需要的是将每行中的时间转换为有意义的时间值,例如unix时代,或使用perl DateTime系列方法进行日期比较。