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

The following snippet works fine, with local $/ = undef and (string=~//g){$count++} syntax gleaned from Catagorized Questions and Answers.   It's the output end of a script which uses UCD-SNMP to check a passel o' Ethernet switches for port occupancy.  

Here's my question - can repetition of lines 16-19 be re-written more concisely?  
    cheers,
    Don
    striving for Perl Adept

1 #!/usr/bin/perl -w 2 3 use strict; 4 5 my $infile = './count.in'; 6 my $vlan = "0"; 7 my $up = "0"; 8 my $down = "0"; 9 my $shut = "0"; 10 11 { 12 local $/ = undef; 13 open(IN, "<$infile") or die "Cannot open $infile: $!"; 14 my $filestring = <IN>; 15 close IN or die "Cannot close $infile: $!"; 16 while ($filestring =~ /VLAN/g) { $vlan++ } 17 while ($filestring =~ /ifOperStatus.*up\(1\)/g) { $up++ } 18 while ($filestring =~ /ifOperStatus.*down\(2\)/g) { $down++ } 19 while ($filestring =~ /ifAdminStatus.*down\(2\)/g) { $shut++ } 20 } 21 22 my $live = ($up - $vlan); 23 my $total = ($live + $down); 24 25 print "$vlan VLAN(s)\n"; 26 print "$total physical ports\n"; 27 print "$live active port(s)\n"; 28 print "$down inactive port(s)\n"; 29 print "$shut disabled port(s)\n";
Sample Input (./count.in)
interfaces.ifTable.ifEntry.ifAdminStatus.1 = up(1) interfaces.ifTable.ifEntry.ifAdminStatus.2 = up(1) interfaces.ifTable.ifEntry.ifAdminStatus.3 = up(1) interfaces.ifTable.ifEntry.ifAdminStatus.4 = up(1) interfaces.ifTable.ifEntry.ifAdminStatus.5 = down(2) interfaces.ifTable.ifEntry.ifOperStatus.1 = up(1) interfaces.ifTable.ifEntry.ifOperStatus.2 = up(1) interfaces.ifTable.ifEntry.ifOperStatus.3 = up(1) interfaces.ifTable.ifEntry.ifOperStatus.4 = down(2) interfaces.ifTable.ifEntry.ifOperStatus.5 = down(2) interfaces.ifTable.ifEntry.ifDescr.1 = VLAN1 interfaces.ifTable.ifEntry.ifDescr.2 = FastEthernet0/1 interfaces.ifTable.ifEntry.ifDescr.3 = FastEthernet0/2 interfaces.ifTable.ifEntry.ifDescr.4 = FastEthernet0/3 interfaces.ifTable.ifEntry.ifDescr.5 = FastEthernet0/4

Replies are listed 'Best First'.
Re: Cut n' paste monkey on my back
by tedv (Pilgrim) on Nov 02, 2000 at 06:33 UTC
    Wouldn't this be a great use for a hash? Just search for any keyword on the line and if you find one, increment the appropriate hash entry. Then read from $output{VLAN}, etc to find these. You should only have 1 match string. Maybe you could do something like this:
    my %flag = (); while (<IN>) { s/\.\d+\s*=\s*/_/; # Format the string to match nicer $flag{$1}++ if /(VLAN|if(?:Oper|Admin)Status_(?:up|down))/; } # Now access $flag{VLAN}, $flag{ifOperStatus_up}, etc.

    I'm not sure if the substitute makes you take more time, but at least you won't parse through the entire file 4 times. Sometimes it really does make more sense to parse the file one line at a time, instead of in a huge block. This particularly makes sense because the lines have such regularity.

    -Ted

      That was the first thing I though of also, although I would write it like this:

      $found{$1}++ while /($foo|$bar|$baz)/go;

      The only problem in general is that $foo and company cannot contain any "special" regular expression character...it will work, but they will return the match, not the original search, i.e. $foo = "ba.t" would create keys of "bart", "bast", and "bait". Still, if you know your input file well enough to avoid them, a simple hash increment is definitely a smooth way to do it.

      Thanks tedv - exactly what I was hoping for.   8^)

      Since the SNMP collection code is in the same script, would it make sense to put the collection data into an array instead of the intermediate file, and read array elements into your code?   Would save having to open+close+unlink file, but are there drawbacks ?
          cheers,
          Don
          striving for Perl Adept

      Update: and thanks to mdillon for esplaining turnstep's /o syntax above.   More food for thought.   But my brain is full.   {g}

RE: Cut n' paste monkey on my back
by geektron (Curate) on Nov 02, 2000 at 03:22 UTC
    off the cuff --

    why read from a file and not just probe the devices directly? i would think that files would get out of date extremely quickly.

    but i don't see a faster way of rewriting the lines in question.

      Hmmm... guess I just hadn't got there yet.

      Think I follow you, though - have UCD-SNMP output to variable instead of intermediate file.   Bear with me here, would you use one scalar for the whole thing, or an array of one-line elements?   Highest portcount chassis in my environment is around 400, and 3 lines per port, so over 1000 lines o' info being scanned.

      ybiC smiles, as he continues to learn wonders of Perl...

        if you're already using UCD-SNMP ( how different is that from SNMP.pm off CPAN?? ), you can do the processing INSTEAD of printing out to the temp file.

        i'm taking a stab in the dark here, but if you're using SNMP to fetch data and write a file, then using another script to parse the file, you'd be better off doing the parsing IN the original 'fetch' script and eliminating the intermediate file.

        with a large environment, you'll probably need to think about run-time, how often the script is run, and consider using fork() for parallel processing. there is an asyncronous polling feature in SNMP.pm. it might help also.

RE: Cut n' paste monkey on my back
by little (Curate) on Nov 02, 2000 at 03:32 UTC
    while $line { @collect = split (".", $line); "evaluate" $collect[3] or @collect[3..$#collect]; }
    untested :-)
(tye)Re: Cut n' paste monkey on my back
by tye (Sage) on Nov 02, 2000 at 04:05 UTC

    Perhaps like this?

    $vlan += $filestring =~ /VLAN/g; $up += $filestring =~ /ifOperStatus.*up[(]1[)]/g; $down += $filestring =~ /ifOperStatus.*down[(]2[)]/g; $shut += $filestring =~ /ifAdminStatus.*down[(]2[)]/g;
            - tye (but my friends call me "Tye")
RE: Cut n' paste monkey on my back (solution and thanks)
by ybiC (Prior) on Nov 03, 2000 at 20:50 UTC
    Thanks for all the help - PMers are the best!

    I ended up tweaking tedv's suggestion into script at "(code) mind your snmPs & Qs".   Still have a bit of work on subtraction for total port count - looks like some switch models are reporting loopback or such as ports.
        cheers,
        Don
        striving for Perl Adept