2017-01-09 2 views
1

Ich habe eine Datei mit der ersten ZeileDatei in Perl-Parsing ersten und letzten Zeilen lesen

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

und letzte Zeile

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

Ich interessiere mich für Zeitfelder in diesen Zeilen (17:41:55 und 17:49:17) , möchte den Unterschied in der Zeit von Anfang bis Ende finden.

Ich habe versucht, die Datei in einem Array zu lesen und erste und letzte Zeile

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

Aber holen in Array Zeitfeld bekommen wird schwierig.

Können Sie bitte irgendeinen alternativen Weg vorschlagen?

+0

[Lesen letzte Zeile] (http://stackoverflow.com/questions/36568162/how- do-ich-lese-die-letzte-Zeile-einer-Datei-mit-einem-bare-perl-on-windows/36570096) – mkHun

Antwort

6

Wenn Sie die erste und letzte Zeile einer möglicherweise sehr großen Protokolldatei lesen möchten, sollten Sie nicht alles in ein Array schlürfen, da es viel Speicher belegen kann. Lesen Sie stattdessen die erste und die letzte Zeile.

Sie können die erste Zeile einfach genug lesen.

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

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

Sie können die letzte Zeile gelesen seek unter Verwendung bis zum Ende der Datei zu springen und dann rückwärts mit read in Stücken zu lesen, bis Sie eine ganze Zeile bekommen. Das kann kompliziert werden. Glücklicherweise gibt es File::ReadBackwards, um das für Sie zu tun.

use Carp; 
use File::ReadBackwards; 

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

Beachten Sie, dass, wenn es am Ende der Datei keine Streu newlines ist wird jene die letzte Zeile, so dass Sie weiter zu lesen möchten, bis Sie bekommen, was Sie suchen.

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

Hier ist ein einfacher, aber langsamer (für große Dateien), um die erste und letzte Zeile zu erhalten. Lies die erste Zeile wie zuvor, lies dann jede Zeile, aber behalte nur die letzte.

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

Es hat immer noch die gesamte Datei zu lesen, aber es hält nur die letzten im Speicher.


Sobald Sie, dass, können Sie die Zeile analysieren und machen es zu einem Time::Piece Objekt mit leichter zu arbeiten.

# === 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 ist eine Funktion von vielen Sprachen verwendet Daten zu analysieren (string Parse-Zeit). strftime (Zeichenfolge Format Zeit) wird zum Formatieren von Daten verwendet. Sie teilen dieselbe Minisprache. Werfen Sie einen Blick auf die strftime Dokumente, um zu verstehen, was dort vor sich geht.

Sobald Sie das haben, 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; 
2

Ich habe einen etwas weniger anspruchsvollen Ansatz zu Schwern, die die Unix verwenden Befehle:

#!/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"; 
+0

Ich glaube 'tail -1' wird vom Ende der Datei gelesen, so Es vermeidet das Lesen der gesamten Datei. Benutze keine Prototypen. Sie sind keine Funktionssignaturen, sie sind für sehr spezielle Zwecke gedacht. Wenn Sie Funktionssignaturen möchten, verwenden Sie in neueren Perls [Method :: Signatures] (http://metacpan.org/pod/Method::Signatures) oder 'feature 'Signaturen'. Schließlich muss man 'command()' nicht schreiben, [backticks] (http://perldoc.perl.org/perlop.html#Quote-Like-Operators) wird das für Sie tun. '' 'my $ first =' head -1 $ ARGV [0] '' '' – Schwern

+1

@Schwern danke, ich glaube ich stehe seit 15 Jahren damit still. Ich habe meine Antwort mit Dank aktualisiert. –

+0

Warum hast du 'use English'? Sie verwenden tatsächlich keine Variablennamen. – simbabque

Verwandte Themen