Необходимо напечатать последнее вхождение строки в Perl

У меня есть скрипт на Perl, который ищет ошибку, которая находится в файле конфигурации, но он распечатывает любое возникновение ошибки. Мне нужно сопоставить то, что находится в файле конфигурации, и распечатать только в последний раз, когда произошла ошибка. Есть идеи?


Ух ты... Я не ожидал такой большой реакции. Я должен был быть более ясным, заявив, что это для мониторинга журналов в окне Windows, которое отправляет предупреждение в Nagios. На самом деле это моя первая программа на Perl, и вся эта информация была очень полезной. Кто-нибудь знает, как я могу применить это любой из хвостовых ответов на коробке wintel?

4 ответа

Еще один способ сделать это:

perl -n -e '$e = $1 if /(REGEX_HERE)/;  END{ print $e }' CONFIG_FILE_HERE

Что именно вам нужно напечатать? Строка, содержащая ошибку? Больше контекста, чем это? File::ReadBackwards может быть полезным

В общих чертах:

my $errinfo;
while (<>)
{
    $errinfo = "whatever" if (m/the error pattern/);
}
print "error: $errinfo\n" if ($errinfo);

Это ловит все ошибки, но не печатает до конца, когда выживает только последняя.

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

Вы не указали, поэтому я предполагаю, что допустимая строка конфигурации имеет вид

Name = some value

Соответствие это просто:

  • ^ (начиная с начала строки)
  • \w+ (один или несколько "символов слова")
  • \s+ (с последующим обязательным пробелом)
  • = (сопровождается знаком равенства)
  • \s+ (более обязательный пробел)
  • .+ (какое-то обязательное значение)
  • $ (заканчивая в конце строки)

Склеив это, мы получим

#! /usr/bin/perl

use warnings;
use strict;

# for demo only
*ARGV = *DATA;

my $pid = open STDOUT, "|-", "tail", "-1" or die "$0: open: $!";
while (<>) {
  print unless /^ \w+ \s+ = \s+ .+ $/x;
}

close STDOUT or warn "$0: close: $!";

__DATA__
This = assignment is ok
But := not this
And == definitely not this

Выход:

 $./lasterr 
И == определенно не это 

С помощью регулярных выражений, когда вы хотите, чтобы последнее вхождение шаблона ^.* в передней части вашего шаблона. Например, чтобы заменить последний X на входе на Y, используйте

 $ echo XABCXXXQQQXX | perl -pe 's/^(.*)X/$1Y/'
XABCXXXQQQXY 

Обратите внимание, что ^ является избыточным, потому что квантификаторы регулярных выражений являются жадными, но мне нравится иметь его там для акцента.

Применяя этот метод к вашей проблеме, вы можете искать последнюю строку в вашем файле конфигурации, которая содержит ошибку, как в следующей программе:

#! /usr/bin/perl

use warnings;
use strict;

local $_ = do { local $/; scalar <DATA> };
if (/\A.* ^(?! \w+ \s+ = \s+ [^\r\n]+ $) (.+?)$/smx) {
  print $1, "\n";
}

__DATA__
This = assignment is ok
But := not this
And == definitely not this

Синтаксис регулярного выражения немного отличается, потому что $_ содержит несколько строк, но принцип тот же. \A похож на ^, но это соответствует только в начале строки для поиска. С /m переключатель ("многострочный"), ^ соответствует границам логической линии.

До этого момента мы знаем схему

/\A.* ^ .../

соответствует последней строке, которая выглядит как-то. Негативное прогнозное утверждение (?!...) ищет строку, которая не является допустимой строкой конфигурации. обычно . соответствует любому символу, кроме новой строки, но /s переключатель ("одна строка") снимает это ограничение. Определение [^\r\n]+ то есть, один или несколько символов, которые не являются ни переводом каретки, ни переводом строки, не позволяют совпадению перетекать в следующую строку.

Проверочные утверждения не фиксируются, поэтому мы берем оскорбительную строку с (.+?)$, Причина, по которой это безопасно использовать . в этом контексте, потому что мы знаем, что текущая строка плохая и не жадный квантификатор +? прекращает сопоставление, как только может, что в данном случае является концом текущей логической строки.

Все эти регулярные выражения используют /x Переключатель ("расширенный режим"), чтобы освободить лишние пробелы: цель - улучшить читаемость.

Другие вопросы по тегам