2012-06-22 72 views
2

我希望寫在Perl解析腳本,打印所有的「接口名稱」從這些數據串的:提取內容用Perl

interfaces.ifTable.ifEntry.ifDescr.1 : OCTET STRING- (ascii): (hex): length = 30 
    0: 53 6f 66 74 77 61 72 65 20 4c 6f 6f 70 62 61 63  Software Loopbac 
    16: 6b 20 49 6e 74 65 72 66 61 63 65 20 31 00 -- --  k Interface 1... 

interfaces.ifTable.ifEntry.ifDescr.2 : OCTET STRING- (ascii): (hex): length = 20 
    0: 57 41 4e 20 4d 69 6e 69 70 6f 72 74 20 28 53 53  WAN Miniport (SS 
    16: 54 50 29 00 -- -- -- -- -- -- -- -- -- -- -- --  TP)............. 

interfaces.ifTable.ifEntry.ifDescr.3 : OCTET STRING- (ascii): (hex): length = 20 
    0: 57 41 4e 20 4d 69 6e 69 70 6f 72 74 20 28 4c 32  WAN Miniport (L2 
    16: 54 50 29 00 -- -- -- -- -- -- -- -- -- -- -- --  TP)............. 

我想提取所有三個接口(「Sotware Loopback Interface 1」,「WAN Miniport(SSTP)」,「WAN Miniport(L2TP)」),並進行進一步處理。我嘗試使用正則表達式,但沒有luch。有沒有簡單的方法來做到這一點?提前致謝!

+2

這看起來更像是一個「unpack」問題,而不是正則表達式問題;輸入數據結構良好。 – DavidO

回答

1

這是又一個骯髒的Perl腳本。無論您希望如何,都可以將數據讀入$文本。正則表達式查找每個十六進制轉儲行的模式。連接線然後將十六進制值重新組合到字符串中,並將其附加到當前的累積接口名稱。 mttrb的更簡單。 ;)

$text =<<EOM; 
interfaces.ifTable.ifEntry.ifDescr.1 : OCTET STRING- (ascii): (hex): length = 30 
    0: 53 6f 66 74 77 61 72 65 20 4c 6f 6f 70 62 61 63  Software Loopbac 
    16: 6b 20 49 6e 74 65 72 66 61 63 65 20 31 00 -- --  k Interface 1... 

interfaces.ifTable.ifEntry.ifDescr.2 : OCTET STRING- (ascii): (hex): length = 20 
    0: 57 41 4e 20 4d 69 6e 69 70 6f 72 74 20 28 53 53  WAN Miniport (SS 
    16: 54 50 29 00 -- -- -- -- -- -- -- -- -- -- -- --  TP)............. 

interfaces.ifTable.ifEntry.ifDescr.3 : OCTET STRING- (ascii): (hex): length = 20 
    0: 57 41 4e 20 4d 69 6e 69 70 6f 72 74 20 28 4c 32  WAN Miniport (L2 
    16: 54 50 29 00 -- -- -- -- -- -- -- -- -- -- -- --  TP)............. 
EOM 

$interface = ""; 
foreach $line (split(/\n/, $text)) { 
    next unless $line =~ /\b(\d+):\s+((?:[0-9a-fA-F-]{2}){16})/; 
    if ($1 == 0) { 
    print "$interface\n" if $interface; 
    $interface = ""; 
    } 
    $interface .= join('', map { chr(hex($_)) } grep { $_ ne '--' && $_ ne '00' } split(/ /, $2)); 
} 
print "$interface\n" if $interface; 

爲了解釋連接線,在該行中會出現以下情況。

  1. split(/ /,$ 2) - 從正則表達式中取出第二個保存的組,它們是十六進制字符,並將其拆分爲包含每對數字的數組。
  2. grep {$ _ ne' - '& & $ _ ne'00'} - 查看數字對數組並過濾掉' - '和'00'條目,只留下有效值。
  3. map {chr(hex($())}} - 針對每個過濾對運行表達式,$是正在處理的對。十六進制將它從一個十六進制()字符串解析爲一個數字,然後chr()將該數字轉換爲相應的字符。
  4. join('',...) - 獲取映射創建的字符數組並創建一個字符串。 ''是用來分隔每個數組項目的字符串,在這種情況下是沒有的。
+2

+1代替使用十六進制。 'pack'H *',$ string'也可以在刪除填充後使用。 – TLP

+0

@Avilo你能解釋一下'$ interface。= join('',map {chr(hex($ _))} grep {$ _ ne' - '&& $ _ ne'00'}這一行的更多細節。 (/ /,$ 2));'嘗試理解,但有點困惑,對不起,我是Perl新手。 – donie

+0

讓我知道如果這沒有幫助! – Avilo

1

以下是一個快速且髒的perl腳本,它將根據示例輸入來執行您想要的操作。它不會很好地處理輸入格式的變化。我已經編寫腳本來從文件中獲取輸入,您需要更改它。

open(INPUT, "interfaces.txt"); 

my $interface; 

while(<INPUT>) { 
     if (/^\s*0:/) { 
       $interface = substr($_, 60, 16); 
     } elsif (/^\s*16:/) { 
       $interface .= substr($_, 61, 16); 

       $interface =~ s/\.+$//; 

       print $interface, "\n"; 
     } 
} 

close(INPUT); 
1

通過使用段落模式(設置$/ = ""),您可以讀取每條記錄並單獨處理行。抓取最後一個字段似乎最簡單的做法是在字段上使用固定的LIMIT來填充空格上的split,因爲十六進制數字的數量似乎是恆定的,我們需要最後一個字段。

use strict; 
use warnings; 
use Data::Dumper; 

$/ = ""; # paragraph mode keeps lines together 

while (<DATA>) { 
    chomp; # removes two newlines after we changed $/ 
    my ($hdr, @data) = split /\n/; # header + 2 lines 
    my ($interface, @nums) = getdata(@data); 
    print Dumper $interface; 
} 
sub getdata { 
    my (@hex, $str); 
    my @data = @_; 
    for (@data) { 
     push @hex, split(' ', $_, 18); # LIMIT set to 18 
     $str .= pop @hex;    # last field is our string 
    } 
    return $str, @hex; # return everything, why not? 
} 

__DATA__ 
interfaces.ifTable.ifEntry.ifDescr.1 : OCTET STRING- (ascii): (hex): length = 30 
    0: 53 6f 66 74 77 61 72 65 20 4c 6f 6f 70 62 61 63  Software Loopbac 
    16: 6b 20 49 6e 74 65 72 66 61 63 65 20 31 00 -- --  k Interface 1... 

interfaces.ifTable.ifEntry.ifDescr.2 : OCTET STRING- (ascii): (hex): length = 20 
    0: 57 41 4e 20 4d 69 6e 69 70 6f 72 74 20 28 53 53  WAN Miniport (SS 
    16: 54 50 29 00 -- -- -- -- -- -- -- -- -- -- -- --  TP)............. 

interfaces.ifTable.ifEntry.ifDescr.3 : OCTET STRING- (ascii): (hex): length = 20 
    0: 57 41 4e 20 4d 69 6e 69 70 6f 72 74 20 28 4c 32  WAN Miniport (L2 
    16: 54 50 29 00 -- -- -- -- -- -- -- -- -- -- -- --  TP)............. 

輸出:

$VAR1 = 'Software Loopback Interface 1...'; 
$VAR1 = 'WAN Miniport (SSTP).............'; 
$VAR1 = 'WAN Miniport (L2TP).............'; 
1

另一種解決方案,使用正則表達式。

use strict ; 
use warnings; 
my $Data = ' 
interfaces.ifTable.ifEntry.ifDescr.1 : OCTET STRING- (ascii): (hex): length = 30 
    0: 53 6f 66 74 77 61 72 65 20 4c 6f 6f 70 62 61 63  Software Loopbac 
    16: 6b 20 49 6e 74 65 72 66 61 63 65 20 31 00 -- --  k Interface 1... 

interfaces.ifTable.ifEntry.ifDescr.2 : OCTET STRING- (ascii): (hex): length = 20 
    0: 57 41 4e 20 4d 69 6e 69 70 6f 72 74 20 28 53 53  WAN Miniport (SS 
    16: 54 50 29 00 -- -- -- -- -- -- -- -- -- -- -- --  TP)............. 

interfaces.ifTable.ifEntry.ifDescr.3 : OCTET STRING- (ascii): (hex): length = 20 
    0: 57 41 4e 20 4d 69 6e 69 70 6f 72 74 20 28 4c 32  WAN Miniport (L2 
    16: 54 50 29 00 -- -- -- -- -- -- -- -- -- -- -- --  TP)............. 
'; 

foreach my $Record ($Data =~ m#\G(.+?)(?:(?=^\s*$)|\z)#gsm) { 
    my $Interface = ''; 
    foreach (split /\n/, $Record) { 
     next if /^\s*$/; 
     next if /OCTET STRING/i; 
     (m#^[^:]+:(?:\s*(?:\w\w|--)\s*){16}(.+)$#); 
     $Interface .= "$1"; 
    } 

    print "$Interface\n"; 
}