如何在特定时间之后从日志文件中打印行

时间:2016-09-09 05:16:42

标签: perl unix

我想要打印所有行,这些行可以说是在 <table> <tr> <th>Firstname</th> <th>Issue</th> <th>Select</th> </tr> <tr> <td>Jill</td> <td>Smith</td> <td> <input type="button" value="Delete" onclick="deleteRow(this)"/> </td> <tr> <td>Eve</td> <td>Jackson</td> <td> <input type="button" value="Delete" onclick="deleteRow(this)"/> </td> </tr> </table> 脚本中function deleteRow(btn) { var row = btn.parentNode.parentNode; row.parentNode.removeChild(row); } localtime函数返回值后发生的。我尝试过类似下面的内容:

perl

如果我使用perl中的actaul time组件替换my $timestamp = localtime(); open(CMD,'-|','cat xyz.log | grep -A1000 \$timestamp' || die ('Could not open'); while (defined(my $line=<CMD>)){ print $line; } 命令中的$timestamp,则会打印行,但不会使用cat变量打印。

有没有其他方法可以打印日志文件中当前时间之后出现的行或者我如何改进上述命令?

4 个答案:

答案 0 :(得分:2)

您的$timestamp永远不会在Perl中进行评估,因为它只出现在单引号中。但为什么要出来shell以匹配字符串并处理文件? Perl要好得多。

首先是直接的方式,然后是基本的方法。完整的脚本显示在第二个示例中。

读取文件,直到找到带有模式的行,然后退出循环。下次访问该文件句柄时,您将进入下一行,并可以在另一个循环中开始打印。

while (<$fh>) { last if /$timestamp/ }

print while <$fh>;

这将打印出文件的一部分,该文件的一部分位于其中任意位置$timestamp的行之后。如果更具体,请调整与时间戳完全匹配的方式。

或者 - 当一行与时间戳匹配时设置一个标志,如果设置了标志则打印。

use warnings 'all';
use strict;

my $timestamp = localtime();

my $logile = 'xyz.log';
open my $fh, '<', $logfile or die "Can't open $logfile: $!";

my $mark = 0;
while (<$fh>) 
{
    if (not $mark) { 
        $mark = 1 if /$timestamp/;
    }
    else { print }
}
close $fh;

答案 1 :(得分:1)

如果您正在使用Shell中的grepping,那么您可以反过来执行此操作并仅调用perl以获得localtime的结果:

 sed <xyz.log -ne"/^$(perl -E'say scalar localtime')/,\$p"

这使用sed的范围寻址:首先将它保留在打印行中,除非使用-n明确告知,在第一次出现时间戳之间选择所有内容(我添加了^以获得良好的衡量标准,如果日志行可以包含纯文本中的时间戳)和文件末尾($)并打印它(p)。

纯Perl解决方案可能如下所示:

my $timestamp = localtime();
my $found;
open(my $fh, '<', 'xyz.log') or die ('Could not open xyz.log: $!');
while (<$fh>) {
    if($found) {
        print;
    } else {
        $found = 1 if /^$timestamp/;
    }
}

答案 2 :(得分:0)

我建议像下面这样的Perlish方法:

open (my $cmd, "<", "xyz.log") or die $!;
#get all lines in an array with each index containing each line
my @log_lines = <$cmd>;

my $index = 0;

foreach my $line (@log_lines){
    #write regex to capture time from line
    my $rex = qr/regex_for_time_as_per_logline/is;
    if ($line =~ /$rex/){
        #found the line with expected time
        last;
    }
    $index++;
}

#At this point we have got the index of array from where our expected time starts.
#So all indexes after that have desired lines, which you can write as below

foreach ($index..$#log_lines){
    print $log_lines[$_];
}

如果您共享一个日志,我可以帮助使用正则表达式。

答案 3 :(得分:0)

您也可以尝试这种方法:

在这种情况下,我尝试打开/ var / log / messages然后将每个行时间戳转换为epoch并查找time()之后发生的所有行

use Date::Parse;
my $epoch_now = time(); # print epoch current time.
open (my $fh, "</var/log/messages") || die "error: $!\n";

while (<$fh>) {
    chomp;
    # one log line - looks like this
    # Sep  9 08:17:01 localhost rsyslogd: rsyslogd was HUPed
    my ($mon, $day, $hour, $min, $sec) = ($_ =~ /(\S+)\s*(\d+)\s*(\d+):(\d+):(\d+)/);

    # date string part shouldn't be empty
    if (defined($mon) && defined($day)
        && defined($hour) && defined($min)
        && defined($sec)) {
        my $epoch_log = str2time("$mon $day $hour:$min:$sec");
        if ($epoch_log > $epoch_now) {
            print, "\n";
        }
    }
}