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,
| [reply] [d/l] [select] |
|
Would you be so kind to paraphrase what you are doing in your code please.
Thank you again.
| [reply] |
|
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,
| [reply] [d/l] [select] |
|
|
| [reply] |
|
#!/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
| [reply] [d/l] |
|
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.
| [reply] [d/l] [select] |
|
|
| [reply] |
|
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 = ();
}
}
}
| [reply] [d/l] [select] |