2

我想用 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)”),并做进一步处理。我尝试使用正则表达式但没有运气。有什么简单的方法可以做到这一点吗?提前致谢!

4

4 回答 4

1

这是另一个肮脏的 perl 脚本。根据需要将数据读入 $text 。正则表达式查找每个十六进制转储行的模式。然后,连接行将十六进制值重新组合回字符串,并将其附加到当前累积的接口名称中。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($ )) } - 对每个过滤的对运行表达式,$是正在处理的对。Hex 将其从 hex() 字符串解析为数字,然后 chr() 获取该数字并将其转换为相应的字符。
  4. join('', ...) - 接收 map 创建的字符数组并从中创建单个字符串。'' 是分隔每个数组项的字符串,在这种情况下什么都没有。
于 2012-06-22T04:30:04.533 回答
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);
于 2012-06-22T04:16:17.100 回答
1

通过使用段落模式(设置$/ = ""),您可以读取每条记录并单独处理行。抓取最后一个字段似乎是最容易split在空白上使用固定LIMIT字段完成的,因为十六进制数字的数量似乎是恒定的,我们想要最后一个字段。

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).............';
于 2012-06-22T05:08:06.663 回答
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";
}
于 2012-06-22T06:57:34.897 回答