在Perl中我试图读取一个日志文件,并且只打印具有两个特定时间之间的时间戳的行。时间格式为hh:mm:ss,这始终是每个日志的第三个值。例如,我会搜索介于12:52:33到12:59:33之间的行
我是Perl的新手,并且不知道采取哪条路线来开始编程。我很确定这会使用某种类型的正则表达式,但对于我的生活,我甚至无法理解那将是什么。有人可以帮助我。
另外,为了使这更加困难,我必须使用核心Perl模块,因为我的公司不允许我使用任何其他模块,直到它们经过测试和验证,对任何系统都没有任何不良影响脚本可以与之交互。
答案 0 :(得分:2)
在伪代码中,你会做这样的事情:
根据您的需要,这可能太高级了,但flip-flop operator ..
会立即浮现在脑海中。
对于从stdin读取文件,这是传统模式:
while (my $line = <>)
{
# do stuff...
}
使用split
可以轻松地将一行划分为字段(请参阅perldoc -f split)。您可能需要按标签或空格分割线条,具体取决于格式。
一旦获得特定字段(包含时间戳),就可以使用自定义的正则表达式来检查它。请阅读perldoc perlre上的内容。
这可能会让你更接近:
use strict;
use warnings;
use POSIX 'mktime';
my $starttime = mktime(33, 52, 12);
my $endtime = mktime(33, 59, 12);
while (my $line = <>)
{
# split into fields using whitespace as the delimiter
my @fields = split(/\s+/, $line);
# the timestamp is the 3rd field
my $timestamp = $fields[2];
my ($hour, $min, $sec) = split(':', $timestamp);
my $time = mktime($sec, $min, $hour);
next unless ($time < $starttime) .. ($time > $endtime);
print $line;
}
答案 1 :(得分:2)
如果知道开始和结束时间,那么你需要一个带触发器操作符的Perl单线程:
perl -ne 'print if /12:52:33/../12:59:33/' logFile
如果您需要一些基础逻辑来确定开始和结束时间,那么将一行内容“展开”为正式脚本:
use strict;
use warnings;
open my $log, '<', 'logFile';
my $startTime = get_start_time(); # Sets $startTime in hh:mm:ss format
my $endTime = get_end_time(); # Sets $endTime in hh:mm:ss format
while ( <$log> ) {
print if /$startTime/../$endTime/;
}
正如以太的评论所指出的,如果没有确切的时间,这将失败。如果有可能,可以改为实现以下逻辑:
use strict;
use warnings;
use autosplit;
open my $log, '<', 'logFile';
my $startTime = get_start_time(); # Sets $startTime in hh:mm:ss format
my $endTime = get_end_time(); # Sets $endTime in hh:mm:ss format
while ( <$log> ) {
my $time = (split /,/, $_)[2]; # Assuming fields are comma-separated
# and timelog is 3rd field
last if $time gt $endTime; # Stop when stop time reached
print if $time ge $startTime;
}
答案 2 :(得分:1)
如果文件中的每一行都有时间戳,那么在'sed'中你可以写:
sed -n '/12:52:33/,/12:59:33/p' logfile
这将回应相关的路线。
有一个Perl程序,s2p,它会将'sed'脚本转换为Perl。
基本的Perl结构如下:
my $atfirst = 0;
my $atend = 0;
while (<>)
{
last if $atend;
$atfirst = 1 if m/12:52:33/;
$atend = 1 if m/12:59:33/;
if ($atfirst)
{
process line as required
}
}
请注意,编写代码时,代码将处理与结束标记匹配的第一行。如果您不想这样,请在测试后移动“最后一个”。
答案 3 :(得分:0)
如果您的日志文件按天隔离,则可以将时间戳转换为秒并进行比较。 (如果没有,请使用my answer to a question you asked earlier中的技术。)
说你的日志是
12:52:32 outside 12:52:43 strictly inside 12:59:33 end 12:59:34 outside
然后用
#! /usr/bin/perl
use warnings;
use strict;
my $LOGPATH = "/tmp/foo.log";
sub usage { "Usage: $0 start-time end-time\n" }
sub to_seconds {
my($h,$m,$s) = split /:/, $_[0];
$h * 60 * 60 +
$m * 60 +
$s;
}
die usage unless @ARGV == 2;
my($start,$end) = map to_seconds($_), @ARGV;
open my $log, "<", $LOGPATH or die "$0: open $LOGPATH: $!";
while (<$log>) {
if (/^(\d+:\d+:\d+)\s+/) {
my $time = to_seconds $1;
print if $time >= $start && $time <= $end;
}
else {
warn "$0: $LOGPATH:$.: no timestamp!\n";
}
}
你会得到以下输出:
$ ./between 12:52:33 12:59:33 12:52:43 strictly inside 12:59:33 end