Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re^2: $_ not set in while <>

by Marshall (Canon)
on Jun 06, 2021 at 02:59 UTC ( #11133574=note: print w/replies, xml ) Need Help??


in reply to Re: $_ not set in while <>
in thread $_ not set in while <>

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.

Replies are listed 'Best First'.
Re^3: $_ not set in while <>
by LanX (Cardinal) on Jun 06, 2021 at 12:46 UTC
    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

Re^3: $_ not set in while <>
by ikegami (Pope) on Jun 06, 2021 at 04:15 UTC

    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.

      The condition is not "dense".
      The condition is whether or not the input line is "quit" or some form of that.
      All that matters is the part after the last comma.

      Works fine for me:

      use strict; use warnings; my $line; while ( (print "list of letters: "),$line=<>, $line !~ /\s*quit|exit|q +\s*$/i) { print "doing something with $line\n"} __END__ Example run: C:\Users\xxx\Documents\PerlProjects\Monks>perl commandloopX.pl list of letters: 234 doing something with 234 list of letters: asdf doing something with asdf list of letters: quit C:\Users\xxx\Documents\PerlProjects\Monks>
      Update: I guess this could be, using "and" instead of comma.
      print() does return a true value, but nobody checks it.
      while ( (print "list of letters: ") and defined ($line=<>) and $line ! +~ /\s*quit|exit|q +\s*$/i)
      The comma operator is completely fine in Perl. This is more common in C code.

      Update: Oh, the parens around the print are required in order to get the prompt onto the screen.
      I never use a while(1) statement except perhaps in a server process.

      Another Update:
      I did run your code. I did require the addition of a "my declaration" for $line.
      Your code does work albeit as wordy and hard to understand as it is.
      I am sure that there are many Monks who will disagree with style issues!

      use strict; use warnings; my $line; while (1) { print "list of letters: "; defined( $line = <> ) or last; $line !~ /\s*quit|exit|q\s*$/i or last; # Do something with $line. } __END__ C:\Users\xxxx\Documents\PerlProjects\Monks>perl commandloopX3.pl list of letters: adf list of letters: 123 list of letters: q

        G'day Marshall,

        I think the issue here is that the OP wrote "read a file", not "read from the keyboard". If the sentinel value is detected, then processing of the file should stop; however, I think it's reasonable to assume that if no sentinel value is detected, then processing of the file should stop at the end of the file.

        Note that in the examples below, I used a common alias of mine:

        $ alias perle alias perle='perl -Mstrict -Mwarnings -Mautodie=:all -MCarp::Always -E +'

        Here's a file that simulates your keyboard input. I've added an extra line that is to be ignored:

        $ cat > pm_11133571.dat 234 asdf quit ignore

        That is processed (almost) identically to your keyboard input:

        ken@titan ~/tmp $ perle 'my $line; while ( (print "list of letters: "),$line=<>, $line + !~ /\s*quit|exit|q\s*$/i) { print "doing something with $line\n"}' p +m_11133571.dat list of letters: doing something with 234 list of letters: doing something with asdf list of letters: ken@titan ~/tmp

        I said "almost" because, as you may have noticed, there's a dangling "list of letters: " prompt as the last line of output.

        However, if there's no sentinel value, processing does not stop at the end of the file; instead, the code is stuck in a loop. Also, warnings are emitted. Both of those things are what ++ikegami predicted.

        Consider this slightly different input file (without a sentinel):

        $ cat > pm_11133571_2.dat 234 asdf ignore

        Here's what happens:

        $ perle 'my $line; while ( (print "list of letters: "),$line=<>, $line + !~ /\s*quit|exit|q\s*$/i) { print "doing something with $line\n"}' p +m_11133571_2.dat list of letters: doing something with 234 list of letters: doing something with asdf list of letters: doing something with ignore Use of uninitialized value $line in pattern match (m//) at -e line 1, +<> line 3. at -e line 1, <ARGV> line 3. Use of uninitialized value $line in concatenation (.) or string at -e +line 1, <> line 3. at -e line 1, <ARGV> line 3. list of letters: doing something with list of letters:

        The screen output stopped there; I used Ctrl-C to get back to my shell prompt. Of course, I could've typed one of the sentinel values (quit|exit|q) but would you expect users to know what those values were; and even if they did, would you expect them to do this in the "production" environment you described.

        Update: I started to compose my response before your post had any updates. After posting, I see you've added three updates. That's not a complaint about the updates; just advice on what I was responding to.

        — Ken

        The condition is not "dense".

        I didn't say it was dense. What does that even mean? At what point does something become dense? How can you claim it is or isn't dense?

        I said the "condition is so dense you missed that it devolves into an infinite loop of prints and warns." You tried to jam so much into a single expression that you got the expression wrong. Worse, and maybe even more importantly, it's very hard to notice that it's wrong because it's so dense. I only noticed when I rewrote your code.

        Works fine for me

        How would you know? You didn't try giving EOF or an error. The fact that your code doesn't handle this immediately stood out after a rewrite.

        I am sure that there are many Monks who will disagree with style issues!

        Sure, but when it's so hard to read that errors crop in, and when the other alternative makes the error obvious, we start leaving the realm of subjectiveness and entering the realm of objectiveness.

        Also, it leaks the $line variable to the surrounding scope.

        Seeking work! You can reach me at ikegami@adaelis.com

Re^3: $_ not set in while <>
by LanX (Cardinal) on Jun 09, 2021 at 12:35 UTC
    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

Re^3: $_ not set in while <>
by Anonymous Monk on Jun 08, 2021 at 17:06 UTC
    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.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (2)
As of 2021-07-26 00:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?