2016-09-13 5 views
1

Я написал функцию, которая использует регулярное выражение и выводит нужную строку из вывода команды. Скрипт работает так, как ожидалось. Но это не поддерживает динамический вывод. В настоящее время я использую regex для «icmp» и «ok» и печатаю значения. Теперь type, destination и return code могут измениться. Существует высокая вероятность того, что команда не возвращает результат вообще. Как мне обрабатывать такие сценарии?Регулярное выражение для печати строки из команды outpout

sub check_summary{ 

    my ($self) = @_; 

    my $type = 0; 
    my $return_type = 0; 

    my $ipsla = $self->{'ssh_obj'}->exec('show ip sla'); 

    foreach my $line($ipsla) { 
    if ($line =~ m/(icmp)/) { 
      $type = $1; 
     } 
     if ($line =~ m/(OK)/) { 
      $return_type = $1; 
     } 
    } 

    INFO ($type,$return_type); 
} 


    command Ouptut : 

    PSLAs Latest Operation Summary 
    Codes: * active,^inactive, ~ pending 

    ID   Type  Destination  Stats  Return  Last 
               (ms)  Code  Run 
    ----------------------------------------------------------------------- 
    *1   icmp  192.168.25.14 RTT=1  OK   1 second ago 
+1

Пока вы технически «используете» регулярные выражения, вы на самом деле не «используете» свою силу, поскольку используете фиксированные подстроки, как шаблоны. Начните здесь http://perldoc.perl.org/perlrequick.html для быстрого обучения. – mp3

+0

Остальная часть документации [perlrequick] (http://perldoc.perl.org/perlrequick.html) [perlre] (http://perldoc.perl.org/perlre.html) [perlreref] (http: // perldoc.perl.org/perlreref.html) [perlretut] (http://perldoc.perl.org/perlretut.html) – mp3

+0

(1) Что такое '$ ipsla'? Для 'foreach' нужен список для перебора - это arrayref? (2) Действительно ли строка интереса (и всегда) выводит последнюю строку вывода команды? – zdim

ответ

2

Обновлено некоторых уточнений - нам нужна только последняя строка


Как будто часто бывает, вам не нужен regex для анализа вывода, как показано. У вас есть поля, разделенные пробелами, и вы можете просто выбрать split и выбрать нужные элементы.

Нам говорят, что представляющая интерес линия является последней строкой выходного сигнала команды. Тогда нам не нужен цикл, но он может взять последний элемент массива с линиями. Пока неясно, как $ipsla содержит вывод - как многострочную строку или, возможно, как arrayref. Поскольку он выводится командой, я буду рассматривать ее как многострочную строку, сродни тому, что возвращает qx. Затем, вместо foreach петли

my @lines = split '\n', $ipsla;  # if $ipsla is a multi-line string 
# my @lines = @$ipsla;    # if $ipsla is an arrayref 

pop @lines while $line[-1] !~ /\S/; # remove possible empty lines at end 

my ($type, $return_type) = (split ' ', $lines[-1])[1,4]; 

Вот некоторые комментарии по этому коду. Дайте мне знать, если потребуется больше.

Мы видим на показанном выходе, что поля до того, что нам нужно, не имеют пробелов. Таким образом, мы можем разделить последнюю строку на пустое пространство на split ' ', $lines[-1] и взять 2-й и 5-й элементы (индексы 1 и 4), по (...)[1,4]. Это наши две необходимые значения, и мы их назначаем.

На всякий случай выход заканчивается пустыми строками, мы сначала удаляем их, делая pop @lines, если последняя строка не имеет пробелов, while $lines[-1] !~ /\S/.Это то же самое, как

while ($lines[-1] !~ /\S/) { pop @lines } 

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

Я предполагаю, что данные начинаются после строки с тире. Установите флаг, как только эта линия будет достигнута, обработайте линию (линии), если флаг установлен. Учитывая остальную часть вашего кода, петля

my $data_start; 
foreach (@lines) 
{ 
    if (not $data_start) { 
     $data_start = 1 if /^\s* -+ \s*$/x; # only dashes and optional spaces 
    } 
    else { 
     my ($type, $return_type) = (split)[1,4]; 
     print "type: $type, return code: $return_type\n"; 
    } 
} 

Это эскиз, пока не появятся разъяснения. Он также предполагает, что линий больше, чем один.

+0

Если «Last Run» представляет интерес, возможно, вы захотите ограничить свой раскол, поскольку поле содержит пробелы. – mp3

+0

@ mp3 В принципе, да, хорошее наблюдение. Однако здесь я просматриваю данные, и только последнее поле содержит пробелы. Нам нужны два предыдущих поля. – zdim

+0

@ mp3 О, я не запускал на вашем _If «Последний прогон» ..._ - извините. Правильно, если бы это было необходимо, нам пришлось бы делать больше работы. Кстати, мы можем затем выбрать элемент '[5]' - номер из этого последнего поля!Если это не может быть «2 минуты 5 секунд» или некоторые такие, конечно. – zdim

0

Я не уверен во всех возможностях вывода этой команды, поэтому мое регулярное выражение может нуждаться в настройке.

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

use strict; 
use warnings; 

sub check_summary { 
    my ($self) = @_; 

    my %results = map { ($_,undef) } qw(Code ID Type Destination Stats Return_Code Last_Run); # Put results in hash, use column names for keys, set values to undef. 

    my $ipsla = $self->{ssh_obj}->exec('show ip sla');  

    foreach my $line (@$ipsla) { 
     chomp $line; # Remove newlines from last field 

     if($line =~ /^([*^~])([0-9]+)\s+([a-z]+)\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s+([[:alnum:]=]+)\s+([A-Z]+)\s+([^\s].*)$/) { 
      $results{Code}  = $1; # Code prefixing ID 
      $results{ID}   = $2; 
      $results{Type}  = $3; 
      $results{Destination} = $4; 
      $results{Stats}  = $5; 
      $results{Return_Code} = $6; 
      $results{Last_Run} = $7; 
     } 
    } 

    # Testing 
    use Data::Dumper; 
    print Dumper(\%results); 
} 

# Demonstrate 
check_summary(); 

# Commented for testing 
#INFO ($type,$return_type); 

Работает на поданной тестовой линии.

EDIT: Регулярные выражения позволяют вам указывать шаблоны вместо точного текста, который вы пытаетесь сопоставить. Это мощное, но сложное время от времени. Чтобы действительно изучить их, вам нужно прочитать документацию Perl Regular Expression.

Регулярные выражения в Perl также позволяют захватывать согласованный текст. Это можно сделать несколько раз в одном шаблоне, так как мы смогли захватить все столбцы с одним выражением. Матчи идут в нумерованных переменных ... $ 1 $ 2

+0

Я верю, что вы не заметили, что вывод команды начинается со следующих строк. поэтому заданное регулярное выражение u пытается сопоставить строки ниже, а не фактический вывод, который требуется. (и всегда) последняя строка вывода команды. .PSLA. Последняя операционная сводка. . Коды: * active,^inactive, ~ pending « – nims

+0

Если я что-то не хватает, мой код рассчитан на соответствие последней строке вашего примера вывода и игнорировать остальные. Вы имеете в виду, что вы просто хотите сопоставить заголовки столбцов, и вас не интересуют значения? – mp3