http://www.perlmonks.org?node_id=11133571

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

Oh great Monks, I have a simple (I think) question of understanding. I want to read a file until I find a line containing a pattern. I tried this:
while (<> and !/pattern/) {}
but it complained about $_ undefined in m// match. So I then made the assignment to $_ explicit like so and it works great:
while (defined($_ = <>) and !/pattern) {}
I am surprised by the need of doing this and would like to understand why. Thank you all!

Replies are listed 'Best First'.
Re: $_ not set in while <>
by LanX (Saint) on Jun 06, 2021 at 00:57 UTC
      I disagree with your recommended code, but not your data.

      For a while loop, I like to write the main exit condition into the while statement. There could be many ways for the loop to exit past the main, expected condition. However, I code the "most likely" case into the conditional statement.

      Example:

      my $line; while ( (print "list of letters: "),$line=<>, $line !~ /\s*quit|exit|q +\s*$/i) {..do something with this line...}
      In the above, a "my" variable cannot be defined and be used within the same comma statement or logical "and" statement, hence the "my $line;" before the loop conditional.

      I do recommend using named variables for all while loops that go into production code.

      In the above, using "and" instead of the "," would be just fine. The truthfulness of a comma statement only has to do with the value of the last part.

        You seem to believe that the OP wants to read manual input from STDIN², but - as kcott noted - the OP said files.

        Please note that an empty diamond <> defaults to <ARGV> .

        And ARGV only defaults to "-" ° if the array @ARGV is empty.

        So if you want to read from STDIN, better say so explicitly by writing <STDIN> .

        from perlop

        Input from <> comes either from standard input, or from each file listed on the command line. Here's how it works: the first time <> is evaluated, the @ARGV array is checked, and if it is empty, $ARGV[0] is set to "-", which when opened gives you standard input. The @ARGV array is then processed as a list of filenames. The loop
        while (<>) { ... # code for each line }
        is equivalent to the following Perl-like pseudo code:
        unshift(@ARGV, '-') unless @ARGV; while ($ARGV = shift) { open(ARGV, $ARGV); while (<ARGV>) { ... # code for each line } }
        except that it isn't so cumbersome to say, and will actually work. It really does shift the @ARGV array and put the current filename into the $ARGV variable. It also uses filehandle ARGV internally. <> is just a synonym for <ARGV>, which is magical. (The pseudo code above doesn't work because it treats <ARGV> as non-magical.)

        NB: took me a while to find this, IMHO this should be at least mentioned/referenced in @ARGV

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        °) IIRC "-" is just an alias for STDIN which can be passed literally as argument at the command line

        ²) STDIN is not necessarily the keyboard, it depends how the program was started

        That condition is so dense you missed that it devolves into an infinite loop of prints and warns. Fixed:

        while (1) { print "list of letters: "; defined( my $line = <> ) or last; $line !~ /\s*quit|exit|q\s*$/i or last; # Do something with $line. }

        Update: Added missing my.

        Hi

        > In the above, a "my" variable cannot be defined and be used within the same comma statement or logical "and" statement, hence the "my $line;" before the loop conditional.

        In that case I'd prefer the c-style for(;;) loop ...

        update

        from https://perldoc.perl.org/perlsyn#For-Loops plus added my logic

          for (my $i = 1; $i < 10; $i++) { ... }
          is the same as this:
          { my $i = 1; while ($i < 10) { ... } continue { $i++; } }

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        Respectfully dissenting here ... I find last if(s) to be quite useful, because you can quite easily have as many of them as you like. Even if (as is quite usually the case ...) the actual "while condition" is a dummy, the series of last if statements which immediately follow it spell-out every one of the possible "exit conditions," one at a time, separately.