【问题标题】:Parsing (partially) non-uniform text blocks in Perl在 Perl 中解析(部分)不统一的文本块
【发布时间】:2013-08-21 16:04:55
【问题描述】:

我有一个文件,其中有几个块,在文件中(以及在变量中,在程序的这一点上)看起来像这样。

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,...

【问题讨论】:

  • 你能发布示例输出吗?
  • 完成。我希望能回答这个问题。
  • 不可能从块的单个样本中推断出输入的一般布局。为什么不将你的块大小减少到仅代表真实块的大小,然后发布 5 个左右的块,以便我们了解块之间的格式可能以何种方式变化?
  • 我发布了第二个区块。它们都像那种输出样式,但具有不同的字段。这够了吗?
  • 没有。再发布大约 3 个输入块,更新您的输出以显示在给定该输入的情况下它的外观,并解释原因。同样,如果您可以将每个块减少到 5 或 6 行来代表您的实际块,这将非常有帮助,这样我们就不必阅读大量不相关的数据来帮助您。

标签: regex perl parsing sed awk


【解决方案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};

【讨论】:

    【解决方案2】:

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

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

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

    一个简单的属性名称数组和一个循环可以非常快速地解决这个问题。

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

    【讨论】:

    • 不需要单个正则表达式;多个查询就足够了。
    【解决方案3】:

    这是在 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
    

    【讨论】:

      猜你喜欢
      • 2012-10-25
      • 1970-01-01
      • 1970-01-01
      • 2011-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-09
      • 1970-01-01
      相关资源
      最近更新 更多