2012-06-22 42 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"; 
}