2016-09-13 20 views
1

我寫了一個使用正則表達式並從命令輸出中打印所需字符串的函數。 該腳本按預期工作。但它不支持動態輸出。目前,我使用正則表達式「icmp」和「ok」並打印值。現在,type,destinationreturn code可能會改變。命令完全沒有返回輸出的可能性很高。我如何處理這種情況?從命令輸出中打印字符串的正則表達式

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

更新一些澄清 - 我們只需要在最後一行


彷彿通常情況下,你不需要正則表達式來解析輸出,如圖所示。你有空間分隔的字段,只需要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/) { 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

如果「最後一次跑步」很有意思,您可能希望限制您的分組,因爲該字段包含空格。 – 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); 

在提交的測試線上工作。

編輯: 正則表達式允許您指定模式,而不是您嘗試匹配的確切文本。有時這很強大但很複雜。您需要閱讀Perl正則表達式文檔才能真正學習它們。

Perl正則表達式還允許您捕獲匹配的文本。這可以在單個模式中多次完成,這就是我們如何用一個表達式捕獲所有列。比賽進入編號變量... $ 1 $ 2

+0

我相信你沒有注意到,命令輸出從下面的行開始。所以指定的正則表達式會嘗試匹配下面的行,而不是實際需要的輸出。該線的利益真的(總是)最後一行的命令輸出「.PSLAs最新的操作摘要 代碼:* active,^ inactive,〜pending」 – nims

+0

除非我錯過了一些東西,我的代碼被設計爲匹配最後一行的示例輸出,並忽略其餘部分。你的意思是你只是想匹配列標題,你不關心的價值觀? – mp3