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

Enlightened ones,
I'm a perl beginner and have a need to write a script that takes the output from a cisco router that looks like this:
permit ip 7.0.0.0 0.255.255.255 10.31.224.0 0.0.3.255 (55164 matches)
permit ip 8.159.0.0 0.0.255.255 any (4908356 matches)
permit ip any host 10.202.11.250
permit tcp any 172.16.96.200 0.0.0.7 established (10421619 matches)
permit udp any host 172.16.68.225 eq tftp (8 matches)

I need to look at each line and if it doesn't have matches log the line to a file. I was thinking I could split the array by spaces and look at the last $line[] but the last $line[] (greping "matches on it) would be variable. Therein lies my question. Sorry if it's a simple one but I'm quite stuck.
If you're interested in what I'm trying to do here: This access-list is quite (outrageously) long and nobody has kept up on removing unneeded lines. This script will eventually check each line for matches for a period of time and remove any lines that do not generate matches after said period of time.
Thanks in Advance!

edited: Sun Mar 9 14:38:05 2003 by jeffa - title change (was: Perl n00b help)

Replies are listed 'Best First'.
Re: Parsing cisco log file
by VSarkiss (Monsignor) on Mar 06, 2003 at 20:28 UTC

    So you want the line printed if it does not end in "matches)"? That could be as simple as:

    while (<STDIN>) { # This is backwards, see update below. # next unless /matches\)$/; # print LOG; print LOG unless /matches\)$/; }
    Assuming you've already opened LOG to the right file, and that you're feeding the file to the program on standard input.

    Or did I misunderstand your question entirely?

    Update
    I forgot to mention, there's a bunch of code and information about working with cisco routers in the monastery. Follow that link, or type "cisco" in the search box at the top of the page. You may find your problem solved already.

    Update 2
    The logic in the original snippet was backwards. Thanks to guha for spotting it.

      Hey thanks! Sorry for asking for help in an obviously basic area, but I'm brand spanking new to perl. Hmm..this will work, but what if I wanted to grab the number of matches (for performance tuning, stick lines that get more hits toward the top of the list)? I would assume I would need to split my array by spaces, and reference by $line but again the last $line that would hold 45454 matches for instance would be variable.

        I'm still not sure what $line or "45454 matches" you're referring to.

        I'm guessing you do want the lines that end in "matches)", but want to do something different with those, like make a list, sorted by number of matches. In that case, the basic logic would be like this:

        while (<STDIN>) { if (/(\d+) matches\)/) { # keep this in a list we'll sort later push @list, [ $1, $_ ]; } else { # same case as before, write it to the log print LOG; } } # Now print out the list we built before in sorted order foreach (sort { $a->[0] <=> $b->[0] } @list ) { print $_->[1]; }
        You can adapt the basic logic in the loop without using more advanced data structures like I just did, but that's a pretty easy way to do it. This will keep all of the file in memory, so hopefully your file is not too huge.

        The data structure that gets built up in @list is an array of arrays; in other words, each element of @list is an anonymous array that gets pushed into each time. Each of those arrays has two elements: the number of matches, and the line itself. Later, the loop works calls sort on the number matches (element 0), and the print outputs the line (element 1). To learn more about those data structures, look at perlreftut and perldsc.