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

Consider this code:
while (<STDIN> != "\n") { print; }
The intent is to print every line entered at the console until a blank line is entered. But it doesn't work. If I put the line in a variable and then test it, it's fine, but I can't test directly against the <FOO> construct. Am I not supposed to do that?

---
A fair fight is a sign of poor planning.

Replies are listed 'Best First'.
Re: Testing filehandles
by jweed (Chaplain) on Jan 03, 2004 at 20:36 UTC
    To further clarify, the
    while (<FH>) { ... }
    construct is magical. Perl sees that, and does something like this:
    while (defined ($_ = <FH>)) { ... }
    Thus, use
    while (($_ = <STDIN>) ne "\n"){ ... }
    to properly emulate this behavior. Also, I believe that use warnings would have detected improper use of numeric comparison, mate.


    Who is Kayser Söze?
    Code is (almost) always untested.
      Or alternatively...
      while (<STDIN>) { last if $_ eq "\n"; }
Re: Testing filehandles
by Anonymous Monk on Jan 03, 2004 at 20:22 UTC

    In the first place, eq is the string equality operator (!= is numeric). In the second place, the result of <STDIN> won't be automatically assigned to $_ because it is part of a more complex expressions (see "IO Operators" in perlop).

Re: Testing filehandles
by pg (Canon) on Jan 04, 2004 at 05:12 UTC
    "but I can't test directly against the <FOO>"

    I think there is one thing has not been quite straightened yet. In fact, you can test directly against <STDIN>, and that is absolutely not a problem. Let's fix the != problem others pointed out, and test with this code:

    use strict; use warnings; while (<STDIN> ne "quit\n") { print ;#I intentionally leave this here, and you will see "Use of +uninitialized value in print at foo.pl line 5, <STDIN> line blah." }

    As others pointed out, $_ does not contain what you entered, but I intentionally leave it as is.

    The real point I want to make here is that, this piece of demo code does quit the while loop when you enter "quit\n", but does not quit on other input.

    The code itself is not much useful, as $_ does not contain what you entered, and you don't have other variable does that. But I do want to have one fact corrected: you can test against <STDIN>.

Re: Testing filehandles
by dominix (Deacon) on Jan 04, 2004 at 01:54 UTC
    while (defined($_ = <>)) { exit if /^$/;print}

    update: As suggested, if there is more processing to come it could be
    while (defined($_ = <>)) { last if /^$/;print}

    --
    dominix
      exit? I think that last is the appropriate construct here...


      Who is Kayser Söze?
      Code is (almost) always untested.
        The intent is to print every line entered at the console until a blank line is entered.
        so, you could exit isn't it ?
        or you could decide to continue with something else to do and in that case , you're right a last is better suited, but that was not the purpose. my code was from a one-liner test
        perl -pe '/^$/ && exit'
        which produce the expexted result and become
        perl -MO=Deparse -pe '/^$/ && exit'
        before I post it :-)
        --
        dominix
      exit is not a good idea, last is a much better idea. exit will stop the execution of the script, last will stop the loop, see the difference in: perl -wle 'print q(X);while(1) { exit; } print q(Y);' and perl -wle 'print q(X);while(1) { last; } print q(Y);'
Re: Testing filehandles
by nothingmuch (Priest) on Jan 04, 2004 at 10:15 UTC
    I would follow most of the above advice, with the added good behavior of comparing against $/ instead of "\n". Even if the delimeter for what you're reading changes, a blank "record" is still blank that way. Moreover, if the code is moved to a socket or equivelent, it gets worse.

    See perlvar for $/, and perlipc for why.

    -nuffin
    zz zZ Z Z #!perl