В Perl я пытаюсь считать файл журнала и распечатаю только строки, которые имеют метку времени между двумя определенными разами. Формат времени является hh:mm:ss, и это всегда - третье значение на каждом журнале. Например, я искал бы строки, которые упадут между 12:52:33 на 12:59:33
Я плохо знаком с Perl и понятия не имею который маршрут взять, чтобы даже начать программировать это. Я вполне уверен, это использовало бы некоторый тип regex, но ни за что в жизни я не могу даже начать понимать, каково это было бы. Мог кто-то помогать мне с этим.
Кроме того, для создания этого более трудным, я должен сделать это с базовыми модулями Perl, потому что моя компания не позволит мне использовать любые другие модули, пока они не были протестированы и проверены не будет никаких вредных воздействий ни на одну из систем, с которыми может взаимодействовать сценарий.
В псевдокоде вы сделаете примерно следующее:
Возможно, это слишком продвинуто для ваших нужд, но оператор флип-флоп
сразу приходит на ум как нечто полезное.
Для чтения файла из 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;
}
Если время начала и окончания известно, вам понадобится однострочный 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/;
}
Как отмечено в комментарии Ether, это не удастся, если точное время не указано. Если это возможно, вместо этого можно реализовать следующую логику:
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;
}
Если каждая строка в файле имеет отметку времени, то в '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
}
}
Обратите внимание, что как написано, код будет обрабатывать первую строку, которая соответствует конечному маркеру. Если вы этого не хотите, переместите «последний» после теста.
Если ваши файлы журналов разделены по дням, вы можете преобразовать метки времени в секунды и сравнить их. (Если нет, воспользуйтесь техникой из моего ответа на вопрос, который вы задали ранее .)
Скажите, что ваш журнал
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