Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

If statement seems to ignore elsif and skips to else

by edgreenberg (Acolyte)
on Sep 25, 2017 at 18:31 UTC ( [id://1200059]=perlquestion: print w/replies, xml ) Need Help??

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

This little gem comes from the logwatch script that reads the fail2ban log. I'm not getting any output, and put the script under the debugger.

while (defined(my $ThisLine = <STDIN>)) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } chomp($ThisLine); if ( ($ThisLine =~ /..,... DEBUG: /) or ($ThisLine =~ /..,... \S*\s*: DEBUG /) or # syntax of 0.7.? f +ail2ban ($ThisLine =~ /..,... INFO: (Fail2Ban v.* is running|Exiting| +Enabled sections:)/) or ($ThisLine =~ /INFO\s+Log rotation detected for/) or ($ThisLine =~ /INFO\s+Jail.+(?:stopped|started|uses poller)/) + or ($ThisLine =~ /INFO\s+Changed logging target to/) or ($ThisLine =~ /INFO\s+Creating new jail/) or ($ThisLine =~ /..,... \S+\s*: INFO\s+(Set |Socket|Exiting|Gam +in|Created|Added|Using)/) or # syntax of 0.7.? fail2ban ($ThisLine =~ /..,... WARNING: Verbose level is /) or ($ThisLine =~ /..,... WARNING: Restoring firewall rules/) ) { if ( $Debug >= 6 ) { print STDERR "DEBUG($DebugCounter): line ignored\n"; } } elsif ( my ($Service,$Host,$NumFailures) = ($ThisLine =~ m/INFO: + (\S+): (.+) has (\d+) login failure\(s\). Banned./)) { if ($Debug >= 4) { print STDERR "DEBUG: Found host $Host trying to access $Se +rvice - failed $NumFailures times\n"; } push @{$ServicesBans{$Service}{$Host}{'Failures'}}, $NumFailur +es; } elsif ( my ($Service,$Host) = ($ThisLine =~ m/ ERROR:\s(.*):\s(\ +S+)\salready in ban list/)) { $ServicesBans{$Service}{$Host}{'AlreadyInTheList'}++; } elsif ( my ($Service,$Host) = ($ThisLine =~ m/WARNING\s*\[(.*)\] +\s*(\S+)\s*already banned/)) { $ServicesBans{$Service}{$Host}{'AlreadyInTheList'}++; } elsif ( my ($Service,$Host) = ($ThisLine =~ m/ WARNING:\s(.*):\s +ReBan (\S+)/)) { $ServicesBans{$Service}{$Host}{'ReBan'}++; } elsif ($ThisLine =~ / ERROR:?\s*(Execution of command )?\'?iptab +les/) { push @IptablesErrors, "$ThisLine\n"; } elsif ($ThisLine =~ /ERROR.*returned \d+$/) { push @ActionErrors, "$ThisLine\n"; } elsif (($ThisLine =~ /..,... WARNING: \#\S+ reinitialization of +firewalls/) or ($ThisLine =~ / ERROR\s*Invariant check failed. Trying to +restore a sane environment/)) { $ReInitializations++; } elsif ($ThisLine =~ /..,... WARNING: is not a valid IP address/ +) { # just ignore - this will be fixed within fail2ban and is harm +less warning } else { # Report any unmatched entries... push @OtherList, "$ThisLine\n"; } }

When I run this under the debugger, and I advance using the "s" command, should I expect the debugger to stop on each of the elsif statements before evaluating it, or should it only stop if the argument is true?

Many Thanks, Ed Greenberg

Replies are listed 'Best First'.
Re: If statement seems to ignore elsif and skips to else
by Laurent_R (Canon) on Sep 25, 2017 at 18:49 UTC
    Hi edgreenberg,

    usually, when stepping through the code, the debugger jumps directly to the (first) matching condition (actually into the code of the matching if block), or directly to the block of the else statement (if any and) if none of the if and elsif conditions is met.

    You will not "see" the debugger "try" the conditions that are evaluated to false.

    Update: a small example:

    $ perl -dE 'my $c = shift; > if ($c == 1) { > say 1; > } elsif ($c == 2) { > say 2; > } elsif ($c == 3) { > say 3; > } else { > say "something else"; > } ' 4 Loading DB routines from perl5db.pl version 1.33 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(-e:1): my $c = shift; DB<1> s main::(-e:2): if ($c == 1) { DB<1> s main::(-e:9): say "something else"; DB<1> s something else Debugged program terminated. Use q to quit or R to restart, use o inhibit_exit to avoid stopping after program termination, h q, h R or h o to get additional info. DB<1>
Re: If statement seems to ignore elsif and skips to else
by ww (Archbishop) on Sep 25, 2017 at 18:56 UTC

    Stop at each elsif? Only if you've set breakpoints at each one, I think... but

    I suspect your first or (at Ln 7) is NOT doing what you expect. You have two alternatives at Ln 8 & 9 (where you start another or clause. Suggest you group your alternatives.

    UPDATE: Miscounted paren pairs. My bad.

    Warning: these observations arise from a top of head scan of your submission... but can't be taken too seriously, since we have no sample of input ... and can't (from what you've shown) be sure we know what $ThisLine may contain.

    Lastly, point of personal preference (only? perhaps?): rather than constucting regexen with fixed dots (for any byte), it may make the code clearer to use quantifiers... and precompiled regexen:

    my $re_start = qr/../; #match string begining with two of anything (0 +or more times each!) # but still a potential problem: would match a +null string) # so, perhaps, qr/.{1).(1)/ which will not allow + a string # (preceding the comma in your initial set of rege +xen) # with anything other than two instances of somethin +g # or another

    untested, but HTH.

    UPDATE: demonstrates the need to test before posting...and the consequences of failing to do so. My bad again


    Spirit of the Monastery but ++$anecdote ne $data

      Even with breakpoints it will not stop on the false if conditions.

      The test program:

      $ cat debugger.pl use strict; use warnings; use feature 'say'; my $c = shift; if ($c == 1) { say 1; } elsif ($c == 2) { say 2; } elsif ($c == 3) { say 3; } else { say "something else"; }
      And now the execution under the debugger, with the insertion of four break points:
      $ perl -d debugger.pl 4 Loading DB routines from perl5db.pl version 1.33 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(debugger.pl:5): my $c = shift; DB<1> b 7 DB<2> b 8 DB<3> b 9 DB<4> b 10 DB<5> s main::(debugger.pl:6): if ($c == 1) { DB<5> s main::(debugger.pl:13): say "something else"; DB<5> s something else Debugged program terminated. Use q to quit or R to restart, use o inhibit_exit to avoid stopping after program termination, h q, h R or h o to get additional info.
      I suspect your first or (at Ln 7) is NOT doing what you expect. You have two alternatives at Ln 8 & 9 (where you start another or clause. Suggest you group your alternatives.

      I don't understand this point. Unless the OP was updated after your post and the update is not cited (in which case edgreenberg is in line to be officially Frowned Upon), all the
          ($ThisLine =~ /..,... DEBUG: /)
      and etc. matching expressions seem to be fully parenthesized and the logic unambiguous. Can you expand on this point?

      my $re_start = qr/../; #match string begining with two of anything (0 +or more times each!) # but still a potential problem: would match a +null string) # so, perhaps, qr/.{1).(1)/ which will not allow + a string # (preceding the comma in your initial set of rege +xen) # with anything other than two instances of somethin +g # or another

      I also don't get the point about  .. matching "two of anything (0 or more times ...)" and therefore possibly matching the "null" (by which I assume you mean empty) string. The only way I can see for the regex object you give in your example to match the empty string is if it is further quantified with some quantifier such as  ? * {0} {0,} that allows zero matches. However,
          qr{ .{1}.{1} }xms
      has the same problem:

      c:\@Work\Perl\monks>perl -wMstrict -le "my $rx_dotdot = qr{ .. }xms; print 'A: match empty string' if '' =~ $rx_dotdot; ;; my $rx_counted = qr{ .{1}.{1} }xms; print 'B: match empty string: counted' if '' =~ $rx_counted; ;; print 'C: match empty string: counted, quantified' if '' =~ m{ $rx_counted? }xms; " C: match empty string: counted, quantified
      The only advantage I can see for the  .{1}.{1} variation is that it makes dot-dot more visually prominent.

      Perhaps some testing is, indeed, called for.


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

Re: If statement seems to ignore elsif and skips to else
by BillKSmith (Monsignor) on Sep 25, 2017 at 19:14 UTC
    The debugger is often more sensitive to format of your script than perl itself is. I suspect that you would see the behavior that you expect if you reformat your script with perltidy.
    Bill

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1200059]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2024-03-28 15:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found