【问题标题】:Perl - reading a file between two time stampsPerl - 在两个时间戳之间读取文件
【发布时间】:2014-06-22 06:07:43
【问题描述】:

我有一个日志文件,我想根据时间戳逐块读取它(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)

【问题讨论】:

    标签: perl parsing time timestamp


    【解决方案1】:

    使用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. 范围触发器中的正则表达式使用隐式的$_ 循环变量,但您已明确告诉foreach 循环使用$line。由于$_ 中没有任何内容,因此您的触发器将始终返回 false。

      2. 您将触发器与正则表达式一起使用意味着只有当它发现行具有您正在寻找的确切时间时,它才会开始和停止返回 true。您的输入参数$ARGV[0] 不允许您指定时间,只能指定日期。最接近的方法是传入“04/24/2014”,这将产生$currentTime == '2014/04/24-00:00:00'$nextTime == '2014/04/24-00:05:00'。这些时间与您的示例输入中的任何行都不匹配。您的更新使用 &lt;=&gt;= 代替,但它仍然可以使用触发器运算符。这就是它的设计目的。

      虽然还有更多问题,所以通过在代码顶部添加以下内容来打开严格模式和警告:

      use strict;
      use warnings;
      

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

      【讨论】:

      • 好的,这清楚地说明了触发器理论。但是我仍然不知道在这种情况下如何使用正则表达式以便触发器可以检测到它?我真的很感激一个示例行或 2。
      【解决方案3】:

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

      // 包含正则表达式,.. 是范围运算符。这意味着您的 if 语句正在这样做:

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

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

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

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

      【讨论】:

      • 我正在使用 awk,例如 (awk '\$0>=from&&\$0
      • 好吧,perl 和 awk 是两个完全不同的野兽……所以你需要更新你的语法才能使用 Perl。
      • 基本上就是这个问题。 :) 需要什么样的改变。我有点失落。
      • 好吧,我不会为你编写代码,但我告诉你要进行哪些更改,并建议了一个模块来帮助你。你看过我的回答吗?你看过那个模块了吗?
      • 我一点也不期待。我不能使用默认 perl 安装中尚未安装的任何模块。无论如何,感谢您的帮助。我现在正在使用 TIME::Local。
      猜你喜欢
      • 2014-06-27
      • 1970-01-01
      • 2011-03-09
      • 1970-01-01
      • 1970-01-01
      • 2011-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多