I would like to first thank those who originally replied to my first article. I have the script modified so it's pulling all the needed data and I finished my work very fast! There was a lot of new syntaxes that I didn't know and took tutorials on each to learn a little more on them.. I'm on my second audit project which requires me to read a Cisco Router config file, pull out the following values:

Interface
Description
Applied ACL INBOUND (IF ANY)
Applied ACL OUTBOUND (IF ANY)
shutdown flag (Yes/No)

I've tried modifying the script given in a response here and came up with garbage :) I will show you what I did to it. I am looking for suggestions on what I am doing wrong so I can fix it. I'm getting hung up on the second inner loop. As once it finds the Interface, I need it to continue a nested loop until it reaches the next ! in the text file

Sample of Text File:

!
interface Serial8/0/2/1:0.304 point-to-point
description Connection to Secret Site X
bandwidth 56
ip address x.x.x.x x.x.x.x
ip access-group ACL_IN in
ip access-group ACL_OUT out
no ip unreachables
frame-relay (omitted code)
!
interface Serial8/0/2/1:0.305 point-to-point
description Connection to Site B
bandwidth 1536
ip address x.x.x.x x.x.x.x
no ip unreachables
frame-relay (omitted code)
!
interface Serial8/0/3/1:0
description Connection to Site A
ip address x.x.x.x x.x.x.x.x
ip access-group ACL123 in
no ip unreachables
!
interface Serial8/0/2/1:0.305 point-to-point
description Connection to Site F
bandwidth 1536
ip address x.x.x.x x.x.x.x
ip access-group ACL123 in
no ip unreachables
frame-relay (omitted code)
shutdown
!

-----------------------------------------

Pseudo-Code
Read the file 'running-config.txt'

LOOP: until the last line of the text file {

find "interface GigabitEthernet" OR "interface Serial" & add to $interface

LOOP: until ! is found {
    find "description" and add to $description
    find "ip access-group"
        if found, add to string
        else add "NO ACL" to $ACL1
    find "ip access-group"
        if found, add to string
        else add "NO ACL" to $ACL2
    find "shutdown" 
        if found, add "YES" to $shutdown
        else add "NO" to $shutdown


END inner LOOP once ! is found and continue outer LOOP
}

PRINT $interface,", ",$ACL1,", ",$ACL2,", ",$shutdown,", ",$description,", " . "\n";
}

Here is the actual code I have:

    #!/usr/bin/perl
    use warnings;
    use strict;
    my $Interface =" ";
    my $description = " ";
    my $group = 'access-group';
    my $group1 = 'access-group';
    my $shutdown = " ";
    my $input_file = 'runningconfig.txt';
    open my $fh, '<', $input_file or die "can't open file:$!";
    while (<$fh>) {
    if (/interface GigabitEthernet/ or /interface Serial/) {
    $Interface = substr $_, ( ( index $_, q{" "} ) + 1 ), $#_;
    while ($_ != '!') 
    {
    if (/description/) {
    my $description = substr $_, ( ( index $_, q{" "}) + 1 ), $#_;
    }
    if (/access-group/){
     my $group = substr $_, ( ( index $_, q{" "}) + 1 ), $#_;}
    if (/access-group/){
     my $group1 = substr $_, ( ( index $_, q{" "}) + 1 ), $#_; }
     if (/shutdown/){
     my $shutdown = substr $_, ( ( index $_, q{" "}) + 1 ), $#_;}
    }
    }
    print "$Interface, $description, $group, $group1, $shutdown.\n";
}   
   #else { next }
   close $fh or die "can't close file:$!";

It displays some wacky stuff and now what I was expecting. Any help would be greatly appreciated.

-Serpterion

Recommended Answers

All 5 Replies

I managed to do it via PHP successfully; however, to further myself in Perl, I am still interested on how I would approach it.. Would it be similar to my PHP script I created?

In Perl I would change the value of the special variable representing the input record separator $/ to '!' to read entire records instead of one line at a time. Then you need only one loop within which you can use regex to capture values into variables.

#!/usr/bin/perl
use warnings;
use strict;

my $filename = 'cisco.txt';
open my $fh, '<', $filename or die "Failed to open $filename: $!";

while (my $rec = get_rec($fh,'!')){
    next if $rec eq '!'; #Skip top line
    my $interface;
    my $description;
    my $acl1;
    my $acl2;
    my $shutdown;
    ($interface) = $rec =~ m/(?:interface Serial|interface GigabitEthernet)(.+)/;
    ($description) = $rec =~ m/(?:description )(.+)/;
    ($acl1,$acl2) = $rec =~ m/(?:ip access-group )(.+)?\n(?:ip access-group )(ACL.+)/;
    ($acl1) = $rec =~ m/(?:ip access-group )(.+)/ unless defined $acl1;
    $acl1 ||= 'NO ACL';
    $acl2 ||= 'NO ACL';
    if ($rec =~ m/shutdown/){
        $shutdown = 'YES';
    }
    else{
        $shutdown = 'NO';
    }
    print $interface,", ",$acl1,", ",$acl2,", ",$shutdown,", ",$description,", " . "\n";
}

sub get_rec{
    my ($fh,$record_separator) = @_;
    local $/ = $record_separator;
    <$fh>;
}

I managed to do it via PHP successfully; however, to further myself in Perl, I am still interested on how I would approach it.. Would it be similar to my PHP script I created?

Thanks for sharing some insight on this, I've tried out the code you've created and recieve this error:

Use of uninitialized value $interface in string eq at cv1.pl line 14, <$fh> line 86.
Use of uninitialized value $interface in print at cv1.pl line 26, <$fh> line 86.
Use of uninitialized value $description in print at cv1.pl line 26, <$fh> line 86.
, NO ACL, NO ACL, NO, ,
Use of uninitialized value $interface in string eq at cv1.pl line 14, <$fh> line 87.
Use of uninitialized value $interface in print at cv1.pl line 26, <$fh> line 87.
Use of uninitialized value $description in print at cv1.pl line 26, <$fh> line 87.
, NO ACL, NO ACL, NO, ,

I suspect since it's reading between the !'s it is not recording a null value for interface because some times there's a ! but no interface such as the beginning of the file:

!
! Last configuration change at 03:17:25 EDT Thu Apr 19 2012 by cw2000
! NVRAM config last updated at 03:17:25 EDT Thu Apr 19 2012 by cw2000
!
version 12.4
service nagle
no service pad
service tcp-keepalives-in
service timestamps debug datetime msec localtime show-timezone
service timestamps log datetime msec localtime show-timezone
service password-encryption
!
hostname Router1
!
boot-start-marker
boot system flash:c2600-adventerprisekx-xxxx.bin
boot-end-marker
!
logging snmp-authfail
logging buffered xxxxxx notifications
logging rate-limit console all 10 except critical
no logging console
enable secret 5 djdkjksjdsSdjlfasldsDS24w
!
!
resource policy
!
aaa new-model
!
!

Immediately after the statement that attempts to find a value for $interface, you can put a statement that skips to the next record if no interface value was found in the current record... next unless defined $interface;

The following works for me:

#!/usr/bin/perl
use warnings;
use strict;

my $filename = 'cisco.txt';
open my $fh, '<', $filename or die "Failed to open $filename: $!";

while (my $rec = get_rec($fh,'!')){
    next if $rec eq '!'; #Skip top line
    my $interface;
    my $description;
    my $acl1;
    my $acl2;
    my $shutdown;
    ($interface) = $rec =~ m/(?:interface Serial|interface GigabitEthernet)(.+)/;
    next unless defined $interface;
    ($description) = $rec =~ m/(?:description )(.+)/;
    ($acl1,$acl2) = $rec =~ m/(?:ip access-group )(.+)?\n(?:ip access-group )(ACL.+)/;
    ($acl1) = $rec =~ m/(?:ip access-group )(.+)/ unless defined $acl1;
    $acl1 ||= 'NO ACL';
    $acl2 ||= 'NO ACL';
    if ($rec =~ m/shutdown/){
        $shutdown = 'YES';
    }
    else{
        $shutdown = 'NO';
    }
    print $interface,", ",$acl1,", ",$acl2,", ",$shutdown,", ",$description,", " . "\n";
}

sub get_rec{
    my ($fh,$record_separator) = @_;
    local $/ = $record_separator;
    <$fh>;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.