匹配并打印阵列中的每个选择

时间:2018-06-21 06:45:08

标签: perl

我有一个脚本,该脚本从数据库收集配置数据并将其存储在数组中。我需要打印找到每个接口并打印设备的配置详细信息。我只会发布需要帮助的部分。

首先,这是从数组中提取的内容:

track 2 interface GigabitEthernet1/6 line-protocol
!
! 
!
!
!
interface Port-channel10.1
 description Enclosure 1 - 3040-1b
 switchport
 switchport trunk encapsulation dot
 switchport trunk allowed vlan 200, 202
 switchport mode trunk
 logging event link-status
 logging event trunk-status
 logging event bundle-status
 logging event spanning-tree status
 shutdown
interface Ethernet1/20
  description tx to something
  switchport mode trunk
  switchport trunk allowed vlan 200-300
  spanning-tree guard root
  speed 1000
  duplex full
interface Bundle-Ether2.1
 description Bundle link to something
 service-policy input qos-pol1
 vrf V17:vodanet
 ipv4 address 10.1.1.1 255.0.0.0
 encapsulation 250
interface Ethernet1/1
  description some interface desc
  switchport mode trunk
  switchport trunk allowed vlan 200-299
  spanning-tree guard root
  duplex full
  no negotiate auto
clock timezone GMT 2 0
line console
  terminal length 48
  ...

因此,每个接口后面不一定都具有相同数量的配置详细信息。我基本上需要采用这些接口配置中的每一个,并分别打印它们。我将这些存储在较小的config-let平面文件中。因此,我需要从interface ...打印到下一个界面之前的最后一项,但是我迷失了搜索的方向。这是我的最新尝试,但是仅当我搜索2个不同的开始/结束字符串时才有效,例如:

foreach (@array) {
    if (/^interface/) {
        $counter = 1;
    } elsif (/duplex/) {
        $counter =0;
      } elsif ($counter) {
            print;
    }
}

这里的问题是我缺少第一个和最后一个字符串,并且并非所有接口都以duplex结尾。我当时在考虑使用行interface的开头,然后在每个双空格分隔项目之后但不确定如何。有人可以帮我找到解决方法吗。

修改

因此,要弄清array,它只是从数据库中抓取并推送到@array的行

1 个答案:

答案 0 :(得分:1)

问题:数组(@lines)具有“接口部分”,它们以/^interface/行开头并一直运行到下一个interface行。最后一部分在第一行不缩进处停止。解析数组中的接口部分。

一种方法:查找数组interface中每条@lines行的索引。然后,连续索引之间的@lines元素就是接口部分。最后一个单独找到。

my @idx = grep { $lines[$_] =~ /^interface/ } 0..$#lines;

for my $i (0..$#idx-1) {
    say "Interface:";
    say "\t$_" for @lines[$idx[$i]..$idx[$i+1]-1];
}

# The last interface section stops at the first unindented line
say "Interface:";
for my $i ($idx[-1] .. $#lines) {
    last if $lines[$i] =~ /^\S/ and $lines[$i] !~ /^interface/;
    say "\t$lines[$i]";
}

最后一个interface段一直到第一个未缩进的行,如注释中所述。

打印"Interface:"只是为了在视觉上区分各个部分。例如,可以将每个接口的行添加到arrayref而不是进行打印。在发布的样本上进行了测试。


另一种方法:遍历@lines,并为每行/^interface/添加一个新的arrayref到具有所有节的数组。然后将行添加到最后一个arrayref。在第一行未缩进的行上退出,该行不是/^interface/

程序从提交的文件(或lines.txt)中获取带有问题示例的行。

use warnings;
use strict;
use feature 'say';

use Data::Dump qw(dd);
use Path::Tiny;

my $file = shift @ARGV or 'lines.txt';

my @lines = path($file)->lines({chomp=>1});

my @if_sections;  # store arrayrefs with lines for each interface

for (@lines) {
    if (/^interface/) {
        push @if_sections, [ $_ ];  # add arrayref for new interface
        next;
    }   
    elsif (/^\S/) { last }

    push @{$if_sections[-1]}, $_;   # add lines to the last arrayref
}

dd \@if_sections;

使用方便的Path::Tiny来读取文件。该模块对故障进行检查和检查。

为了方便起见,使用Data::Dump中的dd来轻松显示数据结构。这是一个具有作为数组引用的元素的数组,因此可以使用它

foreach my $iface (@if_sections) { 
    say "Interface section:";
    foreach my $line (@$iface) {
        say $line;
    }
}

可以通过多种方式更紧凑地编写内容。

请参见教程perlreftut,然后 复杂的数据结构指南perldsc