0

我有一个文件,其中包含几个块,在文件中(以及在变量中,此时在程序中)。

Vlan2 is up, line protocol is up
  ....
     reliability 255/255, txload 1/255, rxload 1/255^M
  ....
  Last clearing of "show interface" counters 49w5d
  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0
  ....
  L3 out Switched: ucast: 17925 pkt, 23810209 bytes mcast: 0 pkt, 0 bytes
     33374 packets input, 13154058 bytes, 0 no buffer
     Received 926 broadcasts (0 IP multicasts)
     0 runts, 0 giants, 0 throttles
     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored
     3094286 packets output, 311981311 bytes, 0 underruns
     0 output errors, 0 interface resets
     0 output buffer failures, 0 output buffers swapped out

这是第二个块,向您展示这些块如何略有不同:

port-channel86 is down (No operational members)
  ...
  reliability 255/255, txload 1/255, rxload 1/255
  ...
  Last clearing of "show interface" counters 31w2d
  ...
  RX
    147636 unicast packets  0 multicast packets  0 broadcast packets
    84356 input packets  119954232 bytes
    0 jumbo packets  0 storm suppression packets
    0 runts  0 giants  0 CRC  0 no buffer
    0 input error  0 short frame  0 overrun   0 underrun  0 ignored
    0 watchdog  0 bad etype drop  0 bad proto drop  0 if down drop
    0 input with dribble  0 input discard
    0 Rx pause
  TX
    147636 unicast packets  0 multicast packets  0 broadcast packets
    84356 output packets  119954232 bytes
    0 jumbo packets
    0 output error  0 collision  0 deferred  0 late collision
    0 lost carrier  0 no carrier  0 babble  0 output discard
    0 Tx pause
  0 interface resets

我想从每个块中挑选出某些数据元素,这些元素可能存在也可能不存在于每个块中。例如,在我发布的第一个块中,我可能想知道有 0 个 runts、0 个输入错误和 0 个溢出。在第二个块中,我可能想知道有 0 个巨型数据包、冲突等。如果给定的查询不在该块中,则只返回 na 是可以接受的,因为这是为了统一处理而设计的。

每个块的结构都与我发布的两个类似;换行符和空格分隔一些条目,逗号分隔其他条目。

我对这可能如何工作有一些想法。我不知道 Perl 中是否有任何类型的“回溯”功能,但我可以尝试查找字段名称(runts、“输入错误”等),然后获取前一个整数;这似乎是最优雅的解决方案,但我不确定它是否可能。

目前,我正在 Perl 中执行此操作。我正在处理的每个“块”实际上是这些块中的几个(由双换行符分隔)。不必在单个正则表达式中完成;我相信可以通过在每个块中应用几个正则表达式来完成。性能并不是一个真正的因素,因为这个脚本可能每小时运行一次。

我的目标是以自动化的方式将所有这些转换为 .csv 文件(或其他一些易于绘制的数据格式)。

有任何想法吗?

编辑:正如我提到的,CSV 中的示例输出,将逐行(对于这样的多个条目)写入文件作为最终结果。如果在块中未找到特定条目,则在相应行中将其标记为 na:

interface_name,txload,rxload,last_clearing,input_queue,output_drops,runts,....
vlan2,1,1,49w5d,0-75-0-0,0,0,....
port-channel86,1,1,31w2d,na,na,0,...
4

3 回答 3

1

属性和数字的简单哈希。

sub extract {
    my ($block) = @_;
    my %r;
    while ($block =~ /(?<num>\d+) \s (?<name>[A-Za-z\s]+)/gmsx) {
        my $name = $+{name};
        my $num = $+{num};
        $name =~ s/\A \s+//msx;
        $name =~ s/\s+ \z//msx;
        $r{$name} = $num;
    }
    return %r;
}

my $block = <<'';
Vlan2 is up, line protocol is up
⋮

my $block2 = <<'';
port-channel86 is down (No operational members)
⋮

use Data::Dumper qw(Dumper);
print Dumper {extract $block};
print Dumper {extract $block2};
于 2013-08-19T19:59:16.987 回答
0

这是在 awk 中执行此操作的一种方法,但这需要进行大量调整才能完美。但同样,使用 SNMP。

awk '{
    printf $1
    for (i=1;i<=NF;i++) {
        if ($i" "$(i+1)~/Input queue:/) printf ",%s",$(i+2)
        if ($i~/runts/) printf ",%s",$(i-1)
        if ($i~/multicast,/) printf ",%s",$(i-1)
    }
    print ""
}' RS="swapped out" file
于 2013-08-19T20:44:33.720 回答
0

我不认为单个正则表达式可以做到这一点,如果可以的话,我也不想支持它。

使用多个正则表达式,您可以轻松使用以下内容:

(\d+) runts
(\d+) input errors
...etc...

一个简单的属性名称数组和一个循环可以很快解决这个问题,而且很少大惊小怪。

如果您可以通过一些预处理将输入分成更小的块,那么您不太可能得到误报。

于 2013-08-19T20:00:20.997 回答