Как искать строки в файле между двумя метками времени, используя Perl? - PullRequest
5 голосов
/ 28 июня 2010

В Perl я пытаюсь прочитать файл журнала и буду печатать только те строки, которые имеют временную метку между двумя определенными моментами времени. Формат времени - чч: мм: сс, и это всегда третье значение в каждом журнале. Например, я бы искал строки, которые упали бы между 12:52:33 до 12: 59: 33

Я новичок в Perl и понятия не имею, какой маршрут выбрать, чтобы даже начать программировать это. Я почти уверен, что это будет использовать какой-то тип регулярных выражений, но для жизни я даже не могу понять, что это будет. Может кто-нибудь, пожалуйста, помогите мне с этим.

Кроме того, чтобы сделать это более трудным, я должен сделать это с основными модулями Perl, потому что моя компания не позволит мне использовать какие-либо другие модули, пока они не будут проверены и проверены, не будет никаких вредных последствий для любой из систем скрипт может взаимодействовать с

Ответы [ 4 ]

2 голосов
/ 29 июня 2010

Если время начала и окончания известно, вам нужен однострочный 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 голосов
/ 28 июня 2010

В псевдокоде вы бы сделали что-то вроде этого:

  • читать в файле построчно:
    • парсит метку времени для этой строки.
    • если оно меньше времени начала, перейдите к следующей строке.
    • если оно больше, чем время окончания, перейдите к следующей строке!
    • else: это строка, которую вы хотите: распечатать.

Это может быть слишком сложным для ваших нужд, но оператор триггер .. сразу приходит на ум как нечто, что было бы здесь полезно.

Для чтения в файле из 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 голос
/ 28 июня 2010

Если каждая строка в файле имеет метку времени, то в '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
    }
}

Обратите внимание, что, как написано, код обработает первую строкуэто соответствует маркеру конца.Если вы не хотите этого, переместите «последний» после теста.

0 голосов
/ 28 июня 2010

Если ваши файлы журнала разделены по дням, вы можете преобразовать временные метки в секунды и сравнить их. (Если нет, используйте метод из моего ответа на вопрос, который вы задавали ранее .)

Скажите, что ваш журнал

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...