2010-06-28 15 views
5

En Perl, estoy tratando de leer un archivo de registro e imprimiré solo las líneas que tienen una marca de tiempo entre dos momentos específicos. El formato de hora es hh: mm: ss y este es siempre el tercer valor en cada registro. Por ejemplo, estaría buscando líneas que cayeran entre 12:52:33 a 12:59:33¿Cómo buscar líneas en un archivo entre dos marcas de tiempo usando Perl?

Soy nuevo en Perl y no tengo idea qué camino tomar para comenzar a programar esto. Estoy bastante seguro de que esto usaría algún tipo de expresión regular, pero por mi vida no puedo siquiera comenzar a comprender lo que sería. ¿Podría alguien por favor ayudarme con esto?

Además, para hacer esto más difícil, tengo que hacer esto con los módulos Core Perl porque mi compañía no me permitirá usar ningún otro módulo hasta que no se hayan probado y verificado que no habrá efectos nocivos en ninguno de los sistemas con los que el script puede interactuar

+1

¿Qué quiere decir con el tercer valor? El tercer campo? – radius

+1

¿Podría publicar un ejemplo de una línea del registro? Eso ayudaría a aclarar las cosas. –

Respuesta

2

En pseudocódigo, usted haría algo como esto:

  • de lectura en el archivo línea por línea:
    • analizar la marca de tiempo para esta línea.
    • si es menor que la hora de inicio, salte a la siguiente línea.
    • si es mayor que el tiempo de finalización, salte a la siguiente línea!
    • else: esta es una línea que desea: imprimirla.

Esto puede ser demasiado avanzada para sus necesidades, pero el flip-flop operator.. inmediatamente viene a la mente como algo que sería útil en este caso.

Para leer en un archivo de la entrada estándar, este es el modelo convencional:

while (my $line = <>) 
{ 
    # do stuff... 
} 

Analizar una línea en los campos se puede hacer fácilmente con split (ver perldoc -f split). Es probable que deba dividir la línea por pestañas o espacios, según el formato.

Una vez que tenga el campo particular (que contiene la marca de tiempo), puede examinarlo usando una expresión regular personalizada. Lea sobre ésos en perldoc perlre.

Aquí hay algo que podría llegar más cerca:

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; 
} 
+0

Y si desea O (logN) en lugar de O (N), puede utilizar la búsqueda binaria en lugar de leer todas las líneas (suponiendo que los archivos de registro estén ordenados por marca de tiempo). – serg

+2

Tal tarea es adecuada para el operador de flip-flop. – Zaid

1

Si cada línea en el archivo tiene el sello de tiempo, a continuación, en 'sed' se podría escribir:

sed -n '/12:52:33/,/12:59:33/p' logfile 

Esto se hará eco de la líneas relevantes

Hay un programa Perl, s2p, que convertirá las secuencias de comandos 'sed' a Perl.

La estructura básica de Perl es a lo largo de las líneas de:

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 
    } 
} 

Tenga en cuenta que tal como está escrito, el código procesará la primera línea que coincide con el marcador final. Si no quiere eso, mueva el 'último' después de la prueba.

0

Si sus archivos de registro están segregados por día, puede convertir las marcas de tiempo en segundos y compararlos. (Si no es así, utilizar la técnica de my answer to a question you asked earlier.)

Digamos que su registro es

12:52:32 outside 
12:52:43 strictly inside 
12:59:33 end 
12:59:34 outside

Luego, con

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

se obtendría la siguiente salida:

$ ./between 12:52:33 12:59:33 
12:52:43 strictly inside 
12:59:33 end
2

Si se conocen los tiempos de inicio y fin, es necesario un trazador de líneas Perl con operador de flip-flop:

perl -ne 'print if /12:52:33/../12:59:33/' logFile 

Si hay alguna lógica subyacente necesaria para que usted pueda determinar las horas de inicio y fin, y luego 'desenróllese' el de una sola línea a una escritura formal:

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/; 
} 

Como notado por el comentario de Ether, esto fallará si el tiempo exacto no está presente. Si esto es una posibilidad, uno podría implementar la siguiente lógica en su lugar:

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; 
} 
+1

Ese condicional fallará si no hay una línea con una marca de tiempo que coincida exactamente con la hora de inicio o finalización. – Ether

+0

@Ether: De acuerdo. Esto es lo que ocurre cuando el OP no especifica suficiente información sobre el problema. – Zaid

Cuestiones relacionadas