Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Parsing out mulitiple blocks of interesting data in files / ignoring other contents

by GeorgMN (Acolyte)
on Mar 02, 2016 at 11:49 UTC ( [id://1156643]=perlquestion: print w/replies, xml ) Need Help??

GeorgMN has asked for the wisdom of the Perl Monks concerning the following question:

dear monks, i have a need to grab repeating blocks of slightly variating data but within non-variating begin and end delimiters. Here is an example:

# contents of file: ! blah ! blah blah ! # start to grab section here with start (/interface/) interface GigabitEthernet1/1/2 description PC Trunk switchport trunk encapsulation dot1q switchport trunk native vlan 100 switchport mode trunk queue-set 2 priority-queue out mls qos trust dscp storm-control broadcast level 1.00 storm-control multicast level 1.00 spanning-tree guard loop channel-protocol lacp channel-group 1 mode active ! # ^ end section with (/!/) # ignore entire block of data when after (/interface/) a (/shutdown/) +is seen before (/!/)" interface GigabitEthernet1/1/3 shutdown ! interface GigabitEthernet1/1/4 shutdown ! interface TenGigabitEthernet1/1/1 ! interface TenGigabitEthernet1/1/2 #*** Begin of sad attempt PL *** #!/usr/bin/perl -w # use strict; use warnings; my $CONFIGFILE = $ARGV[0]; print "$CONFIGFILE\n"; open(FILE, $CONFIGFILE) || die "file not found\n"; while (<FILE>) { if ($_ =~/^interface/../shutdown/) { next; } if ($_ =~/^interface/../!/) { print $_; } }

sadly the above produces no output. Can you help please? Thank you - GT

  • Comment on Parsing out mulitiple blocks of interesting data in files / ignoring other contents
  • Download Code

Replies are listed 'Best First'.
Re: Parsing out mulitiple blocks of interesting data in files / ignoring other contents
by Athanasius (Archbishop) on Mar 02, 2016 at 12:17 UTC

    Hello GeorgMN,

    Although use of the range operator in scalar context (i.e., the flip-flop operator) is often useful for this type of problem, in this case you need a flag which can be set and cleared according to more complicated conditions. The following shows one way to do this:

    #! perl use strict; use warnings; my @block; my $in_block = 0; while (<DATA>) { if (/^interface/) { push @block, $_; $in_block = 1; } elsif ($in_block) { if (/^!/) { print for (@block, $_); @block = (); $in_block = 0; } elsif (/^\s*shutdown/) { @block = (); $in_block = 0; } else { push @block, $_; } } } __DATA__ # contents of file: ! blah ! blah blah ! # start to grab section here with start (/interface/) interface GigabitEthernet1/1/2 description PC Trunk switchport trunk encapsulation dot1q switchport trunk native vlan 100 switchport mode trunk queue-set 2 priority-queue out mls qos trust dscp storm-control broadcast level 1.00 storm-control multicast level 1.00 spanning-tree guard loop channel-protocol lacp channel-group 1 mode active ! # ^ end section with (/!/) # ignore entire block of data when after (/interface/) a (/shutdown/) +is seen before (/!/)" interface GigabitEthernet1/1/3 shutdown ! interface GigabitEthernet1/1/4 shutdown ! interface TenGigabitEthernet1/1/1 ! interface TenGigabitEthernet1/1/2

    Output:

    22:16 >perl 1563_SoPW.pl interface GigabitEthernet1/1/2 description PC Trunk switchport trunk encapsulation dot1q switchport trunk native vlan 100 switchport mode trunk queue-set 2 priority-queue out mls qos trust dscp storm-control broadcast level 1.00 storm-control multicast level 1.00 spanning-tree guard loop channel-protocol lacp channel-group 1 mode active ! interface TenGigabitEthernet1/1/1 ! 22:16 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Would you be so kind to paraphrase what you are doing in your code please. Thank you again.

        The flag variable $in_block keeps track of whether the current line is in a block of interest (because it began with a line starting with the word interface). If we are currently not in such a block, the only thing to be done is to test the current line to determine whether it begins a new such block (if (/^interface/)). If we are already within a block of interest, we will store the current line in the @block array unless the current line (1) begins with the block termination character, !, or (2) begins (after optional whitespace) with the block discard word shutdown.

        When condition (1) is satisfied, we know that the current block has terminated successfully, so we print it out. But if condition (2) occurs, the current block is to be ignored. In either case, the block has ended so we reset the flag to indicate that we are no longer within a block of interest.

        As mentioned above, if we are within a block of interest but the current line satisfies neither condition (1) nor condition (2), then we save the line by pushing it onto the array variable @block, which holds all the lines of the current block that we have read so far. Whenever condition (1) or condition (2) is satisfied, the block ends so we empty the array @block by assigning the empty list to it: @block = ().

        Hope that’s a little clearer,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        What parts of it are causing you trouble?

        But God demonstrates His own love toward us, in that while we were yet sinners, Christ died for us. Romans 5:8 (NASB)

      Hi Athanasius, Sadly the code does not seem not work the way i hoped. Can you help me out further?

      #!/usr/bin/perl -w # use strict; use warnings; my $CONFIGFILE = $ARGV[0]; open(FILE, $CONFIGFILE) || die "file not found\n"; my @block; my $in_block = 0; while (<FILE>) { if (/^interface/) { push @block, $_; $in_block = 1; } elsif ($in_block) { if (/^!/) { print for (@block, $_); @block = (); $in_block = 0; } else { push @block, $_; } } } ######### OUTPUT OF SCRIPT ############ interface Port-channel1 description HIS51-10 switchport trunk encapsulation dot1q switchport trunk native vlan 100 switchport mode trunk storm-control broadcast level 1.00 storm-control multicast level 1.00 spanning-tree guard loop ! interface FastEthernet0 no ip address shutdown ! interface GigabitEthernet1/0/1 switchport access vlan 100 shutdown spanning-tree portfast ! interface GigabitEthernet1/0/2 description Internet Swisscom switchport access vlan 100 speed 1000 duplex full ! interface GigabitEthernet1/0/3 shutdown ! interface GigabitEthernet1/0/4 shutdown ! interface GigabitEthernet1/0/5 shutdown ! interface GigabitEthernet1/0/6 shutdown ! interface GigabitEthernet1/0/7 shutdown ! interface GigabitEthernet1/0/8 shutdown ! interface GigabitEthernet1/0/9 shutdown ! interface GigabitEthernet1/0/10 shutdown ! interface GigabitEthernet1/0/11 shutdown ! interface GigabitEthernet1/0/12 description A-CHHER-IF01-1 /4 switchport access vlan 100 spanning-tree portfast ! interface GigabitEthernet1/0/13 shutdown ! interface GigabitEthernet1/0/14 description A-CHHER-IF01-2 /4 switchport access vlan 100 ! interface GigabitEthernet1/0/15 shutdown ! interface GigabitEthernet1/0/16 shutdown ! interface GigabitEthernet1/0/17 shutdown ! interface GigabitEthernet1/0/18 shutdown ! interface GigabitEthernet1/0/19 shutdown ! interface GigabitEthernet1/0/20 switchport trunk encapsulation dot1q switchport trunk native vlan 100 switchport mode trunk shutdown ! interface GigabitEthernet1/0/21 shutdown ! interface GigabitEthernet1/0/22 shutdown ! interface GigabitEthernet1/0/23 shutdown ! interface GigabitEthernet1/0/24 shutdown ! interface GigabitEthernet1/1/1 description HIS51-10 G1/1/1 switchport trunk encapsulation dot1q switchport trunk native vlan 100 switchport mode trunk queue-set 2 priority-queue out mls qos trust dscp storm-control broadcast level 1.00 storm-control multicast level 1.00 spanning-tree guard loop channel-protocol lacp channel-group 1 mode active ! interface GigabitEthernet1/1/2 description HIS51-10 G1/1/2 switchport trunk encapsulation dot1q switchport trunk native vlan 100 switchport mode trunk queue-set 2 priority-queue out mls qos trust dscp storm-control broadcast level 1.00 storm-control multicast level 1.00 spanning-tree guard loop channel-protocol lacp channel-group 1 mode active ! interface GigabitEthernet1/1/3 shutdown ! interface GigabitEthernet1/1/4 shutdown ! interface TenGigabitEthernet1/1/1 ! interface TenGigabitEthernet1/1/2 ! interface Vlan1 no ip address no ip route-cache shutdown

        You’ve omitted this part of the code:

        elsif (/^\s*shutdown/) { @block = (); $in_block = 0; }

        which tests for the “ignore entire block” keyword shutdown — so of course blocks containing that word are still being printed.

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Parsing out mulitiple blocks of interesting data in files / ignoring other contents
by RonW (Parson) on Mar 02, 2016 at 19:21 UTC

    FWIW, an explanation of why what you tried didn't work.

    /^interface/../shutdown/ will see a line starting with "interface", so the left side of .. will "activate" that instance of .. which will evaluate as "true" until the right side matches a line containing "shutdown". And because the action for the associated if statement is next, all the lines will just be ignored.

    Also, note that the $_ =~ is redundant in this case. A match without a binding operator (=~ or !~) implicitly matches against $_

    Which leads to: If you were intending to match against a specific variable, you would need to write:

    $line =~ /^interface/ .. $line =~ /!/

    otherwise, the left side would match against $line while the right side would match against $_

    One way (not tested) you might still use the scalar range operator (also known as "flip-flop"):

    my @block; my $reject; while (<>) { if (/^interface/ .. /!/) { if (/shutdown/) { $reject = 1; @block = (); } if (not $reject) { unshift @block, $_; } } else { $reject = 0; if (@block > 0) { print @block; @block = (); } } }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1156643]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (3)
As of 2024-04-19 20:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found