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

Ok, it's not a huge issue and has an easy workaround, but I'm curious as to why this does not work. I want to break out of the while loop if an empty string is entered to STDIN. Am I missing something obvious due to sleep deprivation or lack of caffeine?

print " > "; while (chomp( my $line = <STDIN>)){ print " [$line]\n"; } print " > ";

I'm not looking for a solution, I already have that. Just wondering why this doesn't work

Replies are listed 'Best First'.
Re: Empty STDIN does not exit while loop
by choroba (Archbishop) on May 20, 2017 at 07:59 UTC
    chomp returns the number of characters removed. If you entered the "empty string" by pressing <Enter> , then chomp removes the newline and returns 1.

    Using chomp in a while condition is usually not what you want. It'd skip the last line of a file if it didn't end in a newline.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: Empty STDIN does not exit while loop
by Discipulus (Abbot) on May 20, 2017 at 07:37 UTC
    After chomping, check what remains; exit the loop if nothing is found.

    last if $line=~/^$/; # or using length..

    UPDATE: you can also use last unless $line; to quit the loop, but this breaks if 0 is passed. If 0 is valid you can last unless defined $line; see below Laurent_R.

    Additionally if move the chomp inside the loop you can use CTRL-Z to end fidding STDIN

    Notice that chomp returns the number of removed chars, not the chomped string (added in the same time of the below answer..). Considering this and avoiding extra variable $line you can have anything in the while condition:

    while ( chomp ( $_ = <STDIN>) and length $_){ print " [$_]\n"; }

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      you can also use last unless $line; to quit the loop, but this breaks if 0 is passed. If 0 is valid you can last unless defined $line;
      The last unless defined $line; statement will not work either, because even if $line is empty, it will still be defined.

      Your original solution, i.e. last if $line=~/^$/; (or length $line ...), is definitely better.

Re: Empty STDIN does not exit while loop
by haukex (Bishop) on May 20, 2017 at 08:28 UTC

    In general I'd recommend avoiding the pattern while(chomp(<$handle>)) because it often suffers from issues (another explanation).

    You might also want to consider using a module for prompting.

    use IO::Prompt 'prompt'; my $resp = prompt("Foo? ", -yn); use Term::ReadLine; my $term = Term::ReadLine->new; my $line = $term->readline("Bar? ");

    Or even this (the advantage being ExtUtils::MakeMaker is a core module, even though it has a completely different purpose):

    use ExtUtils::MakeMaker 'prompt'; my $value = prompt("Quz?","n");

    The module does have another advantage: "If prompt() detects that it is not running interactively and there is nothing on STDIN or if the PERL_MM_USE_DEFAULT environment variable is set to true, the $default will be used without prompting. This prevents automated processes from blocking on user input."

    Update 2020-11-30: See also the more powerful IO::Prompter, simple example here.

Re: Empty STDIN does not exit while loop
by Marshall (Canon) on May 20, 2017 at 09:14 UTC
    As others have said, while (chomp( my $line = <STDIN>)){} doesn't work because chomp returns the number of characters removed. A "blank" input line will have at least the line ending characters - chomp() will remove them and return how many. So you will never get 0 (zero), even for a "blank" line.

    For terminal user input, I recommend following normal unix conventions: any white space in front does not matter and any white space after the input does not matter. You do not need chomp() when using s/\s*$//; because all line endings are considered white space.

    I strongly prefer to put the condition that "ends the loop" in the loop conditional instead of burying it somewhere within the loop's body. With the "comma operator", the only part of the statement that matters for "truthfulness" is the last clause. If there are say 9 things that can end the loop, I would try to put the very most common of those in the conditional and leave the other 8 to be within the loop (e.g. last if XYZ;).

    For terminal input like this, consider the following 2 examples:

    First, simple Blank Line to exit:

    #!/usr/bin/perl use strict; use warnings; my $line; # don't put a my declaration in a loop conditional print "Enter data at prompt, blank line to finish data entry\n"; while ( (print "> "), $line = <STDIN>, $line !~ /^\s*$/) { $line =~ s/^\s*//; # delete leading spaces $line =~ s/\s*$//; # delete trailing spaces # no chomp is needed because both # carriage return and line feed are # white space characters (\s) in Perl # regex lingo print "Data processed:$line\n"; } print "LOOP EXITED DUE TO BLANK LINE\n";
    Second, using QUIT, quit or any variation like QuIt to quit:
    #!/usr/bin/perl use strict; use warnings; my $line; # don't put a my declaration in a loop conditional print "Enter data at prompt or type: quit to stop data entry\n"; while ( (print "> "), $line = <STDIN>, $line !~ /^\s*Q(uit)$/i) { $line =~ s/^\s*//; # delete leading spaces $line =~ s/\s*$//; # delete trailing spaces # no chomp is needed because both # carriage return and line feed are # white space characters (\s) in Perl # regex lingo print "Data processed:$line\n"; } print "LOOP EXITED DUE TO QUIT \n";
    update: changed typo goof in the # comments of \w to \s.
Re: Empty STDIN does not exit while loop
by BillKSmith (Prior) on May 20, 2017 at 13:37 UTC
    I understand that you are not looking for a solution, but I still recommend that you avoid the problem by using a prompt module (my favorite is IO::Prompt::Hooked). This module handles the prompt, chomp, and empty string correctly without your writing any code at all. It provides options to specify error detection and processing.
    Bill
Re: Empty STDIN does not exit while loop
by johngg (Canon) on May 20, 2017 at 10:22 UTC

    Another way would be to use eof.

    ... while ( not eof( STDIN ) ) { chomp( my $line = <> ); ... } ...

    I hope this is of interest.

    Update: Ignore this, I misread the question :-}

    Cheers,

    JohnGG