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

Hello everyone,
I'm attempting to parse the output of 'show access-list' over a period of days to determine if a line in the access-list does not receive a hit over a period of time. Please see my earlier post: Parsing cisco log file

Below is the code I've come up with, I'm running into trouble with the last portion where I compare lines that have not received matches during day one to lines that haven't received matches on day two. I get nothing at all for output, any thoughts on where I have screwed up or how I can do this better would be much appreciated.

We're storing the output of sh access-list from a cisco #router in a file once a day for 30 days. This script will eventually look at all 30 files and output the access-list entries that have not recieved a match in all 30 files and therefore can be removed.

#/usr/bin/perl #Prompt for the files we want to compare, for now just two print "Enter filename that contains output of show access <list\n"; chomp ($aoutput = <STDIN>); print "Enter the second file\n"; chomp ($aoutput1 = <STDIN>); #Open our files open (IN, $aoutput) || die "Couldn't open $aoutput $!"; open (LOG, ">>matches.txt") || die "Couldn't open matches.txt $!"; open (IN1, $aoutput1) || die "Couldn't open $aoutput1 $!"; #Push each line in file 1 that does not get any matches into an array while (<IN>){ push @aoutput unless /matches\)$/; } #Push each line in file 2 that does not get any matches into an array while (<IN1>){ push @aoutput1 unless /matches\)$/; } #See if the lines that didn't get matches on day 1 #didn't get matches on day 2 as well #Gotta be a better way to do this? while (<@aoutput>){ $linetemp = grep {/$_/i} @aoutput1; if ($_ = $linetemp) { print $_; } }

edited: Fri Mar 14 23:17:01 2003 by jeffa - code tags

Replies are listed 'Best First'.
Re: Parsing cisco router command output (potential answer, untested)
by ybiC (Prior) on Mar 14, 2003 at 20:03 UTC

      Hiya routedude,
    I added <code> tags around your example code, and tweaked some to make it clearer to my short-bus brain.   I found this syntax for matching-the-intersection-of-two-arrays on page 106 of The Perl Cookbook, and also moved the file opens/closes as close to each ofther as possible - always a good habit.
     
    Anyways, I *think* this will do what you want or at least be close.   Wiser monks than I might show how to make it scale to more than just two days' acl log files.   The 'while... push unless /matches/' chunks could likely become a subroutine, but as is, this maybe shows some direction.
      cheers,
      ybiC
        striving toward Perl Adept
        (it's pronounced "why-bick")

    ==untested==
    #/usr/bin/perl -w use strict; # define output+input filenames: my $outFile = 'aclLog.txt'; print "Enter filename that contains output of show access <list\n"; chomp my $aclMatchesDay2 = <STDIN>; print "Enter the second file\n"; chomp my $aclMatchesDay2 = <STDIN>; # check for no-matches in first input file: open (ACLM1, $aclMatchesDay1) or die "Couldn't open $aclMatchesDay1: $ +!"; while (<ACLM1>){ push @noMatchesDay1 unless /matches/; } close ACLM1 or die "Couldn't close $aclMatchesDay1: $!"; # check for no-matches in second input file: open (ACLM2, $aclMatchesDay2) or die "Couldn't open $aclMatchesDay2: $ +!"; while (<ACLM2>){ push @noMatchesDay2 unless /matches/; } close ACLM2 or die "Couldn't close $aclMatchesDay2: $!"; # check for overlap betwixt two input files: my %isect; foreach $e (@noMatchesDay1, @noMatchesDay2){ $isect{$e}++; } my $noMatchesEver = keys %isect; # print said overlap to output file: open (OUT, ">>$outFile") or die "Couldn't open $outFile: $!"; print "$_\n" for @noMatchesEver; close OUT or die "Couldn't close $$outFile: $!";
Re: Parsing cisco router command output
by Enlil (Parson) on Mar 14, 2003 at 20:31 UTC
    Lets go through this line by line (much of this was caught with the warnings and strict pragmas)
    1 #/usr/bin/perl 2 3 print "Enter filename that contains output of show access <list\n" +; 4 chomp ($aoutput = <STDIN>); 5 print "Enter the second file\n"; 6 chomp ($aoutput1 = <STDIN>); 7 8 open (IN, $aoutput) || die "Couldn't open $aoutput $!"; 9 open (LOG, ">>matches.txt") || die "Couldn't open matches.txt $!"; 10 open (IN1, $aoutput1) || die "Couldn't open $aoutput1 $!"; 11 #Push each line in file 1 that does not get any matches into an ar +ray 12 while (<IN>){ 13 push @aoutput unless /matches\)$/; 14 } 15 #Push each line in file 2 that does not get any matches into an ar +ray 16 while (<IN1>){ 17 push @aoutput1 unless /matches\)$/; 18 } 19 20 #See if the lines that didn't get matches on day 1 didn't get matc +hes on day 2 as well 21 22 #Gotta be a better way to do this? 23 24 25 while (<@aoutput>){ 26 $linetemp = grep {/$_/i} @aoutput1; 27 if ($_ = $linetemp) { 28 print $_; 29 } 30 }
    Line 1. You probably need to change this to #!/usr/bin/perl Though you might not depending on the system you are running (I know the AS Perl for windows will associate .pl files with perl).
    Line 2. You should add use strict; here :)
    Line 13. Warnings would have told you that this line does nothing: Useless use of push with no values at E:\111.pl line 13. What you probably meant was something like:
    push @aoutput, $_ unless /matches\)$/;
    Line 17. See line 13, same issue.
    Line 25. I would assume you want a for loop as opposed to a while loop.
    Line 26. I would think that if there were anything in @aoutput1 that everything would match. Also you wanted @linetemp, as opposed to $linetemp.
    Line 27. $_=$linetemp will always evaluate to true, as long as $linetemp something Perl considers true.

    Regardless this code will not do what you want. The way I would go about it is.

    == A Different Approach ==

    1. Open the day two file and grab all the lines you want and put them in a hash. Something like:

    unless (/matches\)$/) { $no_match_day_two{$_} = 1 }
    2. Open the day one files and do the same.
    3. If i want to see the lines in day two that were not in day one, something like this would work (though with a few changes it can be made to show the ones in day one that were not in day two:
    foreach my $match ( keys %no_match_day_two ) { print $match unless exists $no_match_day_one{$_}; }
    As for an array of day one stuff not in day two something like this would work:
    @nmday_one_but_not_nmdtwo = grep { exists $no_match_day_two{$_} } keys + %no_match_day_one;
    I hope this helps.

    -enlil

Re: Parsing cisco router command output
by Vorlin (Beadle) on Mar 14, 2003 at 22:05 UTC
    For your code at the bottom that runs the 'while (<@aoutput>)', you could do somthething like this (my own test code):
    @a = qw(a b c d e f); @b = qw(1 2 c 3 4 f); foreach $foo (@a) { if ( grep /$foo/, @b ) { print "Matched $foo in both arrays\n"; } }
    The above only works if both arrays are populated of course (but will return nothing if an either array is empty). There's probably better ways to do this but it's a good Q&D, hehe...