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

Hi all, after some advice. I'm opening a file and reading through it and look for some key values after the "Count:" text, but my next if's don't seem to be working properly (as they're probably not doing what I think they're doing) and instead it seems to be ignoring the next ifs and just picking up every occurrence of "Count:"

The input file

Checks: Running 'show port | match "Up Yes" | count' Count: 23 lines Checks: Running 'show router interface | match "Up " | count' Count: 4 lines

My Code

open( INPUT, "$folder/$file" ) or die("Could not open $file file"); while ( my $line = <INPUT> ) { next if ( $line =~ m/show port/ ); if ( $line =~ m/Count:\s+(\d+)/ ) { $checks{port}{$stage} = $1; } next if ( $line =~ m/show router interface/ ); if ( $line =~ m/Count:\s+(\d+)/ ) { $checks{l3}{$stage} = $1; } }

Printing out $checks{port}{$stage} shows:

23 4

When it should only show 23 for $checks{port}{$stage} and 4 for $checks{l3}{$stage}...

And a Dumper

$VAR1 = { 'card' => { 'post' => '28615', 'pre' => '28615' }, 'l3' => { 'post' => '28615', 'pre' => '28615' }, 'subs' => { 'post' => '2', 'pre' => '2' }, 'bfd' => { 'post' => 0, 'pre' => 0 }, 'binding' => { 'post' => '28615', 'pre' => '28615' }, 'ospf' => { 'post' => '2', 'pre' => '2' }, 'port' => { 'post' => '28615', 'pre' => '28615' }, 'ldp' => { 'post' => '14', 'pre' => '14' } };

Note, there's other occurrences of "Count" it's picking up but I only included two from the data source to keep things short. Any help is greatly appreciated.

Replies are listed 'Best First'.
Re: Iterating and pattern matching on input file
by roboticus (Chancellor) on Jul 31, 2018 at 20:06 UTC

    bartrad:

    Take a look at what the code in your while loop would do for each line of code:

    • Checks: Running 'show port | match "Up    Yes" | count'
      OK, it matches /show port/, so it would skip rest of the body of the while loop.
    • Count: 23 lines
      It doesn't match /show port/, so it goes to the next line in the loop.
      It matches /Count:\s+(\d+)/, so it would add the value to $checks{port}{$stage}
      It doesn't match /show router interface/, so it goes to the next line in the loop.
      It matches /Count:\s+(\d+)/, so it would add place the value to in $checks{l3}{$stage}
      There's nothing else in the loop to do...
    • Checks: Running 'show router interface | match "Up " | count'
      It doesn't match /show port/, so it goes to the next line in the loop.
      It doesn't match /Count:\s+(\d+)/, so it ignores the body of the if statement.
      It matches /show router interface/, so it would skip the rest of the body of the while loop.
    • Count: 4 lines
      It doesn't match /show port/, so it goes to the next line in the loop.
      It matches /Count:\s+(\d+)/, so it would add the value to $checks{port}{$stage}
      It doesn't match /show router interface/, so it goes to the next line in the loop.
      It matches /Count:\s+(\d+)/, so it would add place the value to in $checks{l3}{$stage}
      There's nothing else in the loop to do...

    So it looks like you're expecting 'next' to mean "read the next line" instead of "ignore the rest of the loop".

    I expect you probably want something like:

    while (my $line = <INPUT>) { my item = "UNKNOWN"; if ($line =~ /show port/) { $item = "port"; } if ($line =~ /show router interface/) { $item = "l3"; } if ($line =~ /Count:\s+(\d+)/) { $checks{$item}{$stage} = $1; } }

    Update: Pressed "create" just a bit too soon!

    Update: As AnomalousMonk mentions, it's not adding the count value.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      It matches /Count:\s+(\d+)/, so it would add the value to ... [emphasis added]

      I agree with your analysis, except I would say "It matches /Count:\s+(\d+)/, so it would assign the value to ... (overwriting the previous value)." (The phrase "add the value to" suggests something like the  += operation (update: but the OPed code does an assign).)


      Give a man a fish:  <%-{-{-{-<

      Thanks for your response. Yeah, that's exactly what I want - "next line", rather than "next". I've updated the code but doesn't seem to be working?

      my $item = "UNKNOWN"; if ( $line =~ m/show port/ ) { $item = + "port"; } if ( $line =~ m/show router interface/ ) { $item = + "l3"; } if ( $line =~ m/Count:\s+(\d+)/ ) { $checks{$item}{$stage} = + $1; }
      $VAR1 = { 'subs' => { 'post' => '2', 'pre' => '2' }, 'bfd' => { 'post' => 0, 'pre' => 0 }, 'ospf' => { 'post' => '2', 'pre' => '2' }, 'UNKNOWN' => { 'post' => '28615', 'pre' => '28615' }, 'ldp' => { 'post' => '14', 'pre' => '14' } };

      Am I missing something?

        bartrad:

        I can't tell what's wrong as you don't show the input data, nor is there enough code to see what's happening.

        From what you're showing me, I'd guess that there's a spelling error in there and the items you're trying to capture are treated as UNKNOWN.

        You might try showing a bit more of your code and/or your test data.

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.