文件解析perl读取第一行和最后一行

时间:2017-01-09 07:31:44

标签: perl

我有第一行的文件

=== Verbose logging started: 1/3/2017  17:41:55  Build type: SHIP UNICODE 5.00.7601.00  Calling process: C:\Windows\SysWOW64\msiexec.exe ===

和最后一行

=== Verbose logging stopped: 1/3/2017  17:49:17 ===

我对这些行中的时间字段感兴趣(17:41:5517:49:17),想要找到从开始到停止的时间差异。

我尝试在数组中读取文件并获取第一行和最后一行

my $last = pop (@array);
my $first = shift (@array);

但是在阵列中进入时间领域变得越来越困难。

你能否建议任何其他方式?

2 个答案:

答案 0 :(得分:7)

如果要读取可能非常大的日志文件的第一行和最后一行,则不应将其全部插入到数组中,因为它可能会占用大量内存。相反,只需阅读第一行和最后一行。

您可以轻松阅读第一行。

 use v5.10;
 use strict;
 use warnings;
 use autodie;

 open my $fh, $logfile;
 my $first = <$fh>;

您可以使用seek跳转到文件的末尾,然后使用read向后阅读,直到您获得整行,就可以阅读最后一行。这可能会变得复杂。幸运的是,有File::ReadBackwards为你做这件事。

use Carp;
use File::ReadBackwards;

my $backwards = File::ReadBackwards->new( $logfile )
    or croak "Can't open $logfile: $!";
my $last = $backwards->readline;

请注意,如果文件末尾有任何杂散换行符,那么这将是最后一行,因此您可能希望继续阅读,直到找到所需内容。

# Read lines backwards until we get something that
# contains non-whitespace.
while( my $last = $backwards->readline ) {
    last if $last =~ /\S+/;
}

这是一个更简单但更慢(对于大文件)获取第一行和最后一行的方法。像以前一样读取第一行,然后读取每一行,但只保留最后一行。

my $last;
while( my $line = <$fh> ) { $last = $line }

它仍然必须读取整个文件,但它只保留最后一个文件。

完成后,您可以解析该行并将其转换为Time::Piece对象,以便更轻松地使用它。

# === Verbose logging started: 1/3/2017  17:41:55 ... ===
# === Verbose logging stopped: 1/3/2017  17:49:17 ===
sub log_time {
    my $line = shift;

    # This captures the 1/3/2017  17:49:17 part
    my($datetime) = $line =~
        /^=== Verbose logging (?:started|stopped):\s*(\d+/\d+/\d+\s+\d+:\d+:\d+)/;

    # Parse it into a Time::Piece object.
    return Time::Piece->strptime($datetime, "%m/%d/%Y %H:%M:%S");
}

strptime是许多语言用来解析日期的函数(字符串解析时间)。 strftime(字符串格式时间)用于格式化日期。他们共享相同的迷你语言。看看strftime文档,了解那里发生了什么。

完成后,you can get the difference in seconds by subtracting them

my $start = log_time($first);
my $end   = log_time($last);

say "Seconds elapsed: ".$end - $start;

答案 1 :(得分:2)

我对Schwern采用一种稍微不那么复杂的方法就是使用Unix命令:

#!/usr/bin/perl

use strict;
use English;

my $first=`head -1 $ARGV[0]`;
my $last=`tail -1 $ARGV[0]`;

print "$first\n";
print "$last\n";