Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

next in while loop not honored

by mitchreward (Acolyte)
on Nov 05, 2014 at 16:06 UTC ( [id://1106220]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, fellow monks
I have a logfile composed of 7 lines;
I'd like to start processing at line X and stop at line N;
This next exit the while and I cant get why, could you help ?

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $maxline = 5; open my $info, "testlog" or die "Could not open $!"; my $start = 2; my $count = 0; while( my $line = <$info>) { next if $count < $start; print $line; last if ++$count == $maxline; print "$count \n"; }

Replies are listed 'Best First'.
Re: next in while loop not honored
by MidLifeXis (Monsignor) on Nov 05, 2014 at 16:20 UTC

    The first check you have in your while loop is if $count < $start, at which point you bounce to reading the next line in your file. The next time through the loop, you again compare $count < $start, which are the same as the first time through the loop, and again bounce to reading the next line in your file. This repeats until your file handle is exhausted. You never update your counter.

    --MidLifeXis

Re: next in while loop not honored
by choroba (Cardinal) on Nov 05, 2014 at 16:21 UTC
    The next doesn't exit the loop, it reiterates it, i.e. goes back to its start and checks it condition. The condition reads in a new line, but it doesn't change neither $count nor $start. So, the next at line 16 is called for every line of the log.

    BTW, to keep track of the input file line numbers, you can use $..

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: next in while loop not honored
by Eily (Monsignor) on Nov 05, 2014 at 16:22 UTC

    When next is applied, you jump to the next iteration (read a new line) without incrementing your $count. So its value is always 0.

    Instead of count, you could use the special var $., which is the current line number. And then, there is an operator that has the "from".."to" semantic in perl, it is the .. or flip flop operator. You can use it like that:

    while (<DATA>) { if (condition1..condition2) { # Here only the line from the moment condition1 is true, until con +dition2 is reached are processed } }
    And the flip flop operator happens to have a bit of DWIM magic, that makes it check the line number (ie $.) if instead of conditions you use numbers:
    while (<DATA>) { next unless 3..7; # ignore all lines except between 3 and 7 include +d print; } __DATA__ One Two Three Four Five Six Seven Eight Nine

Re: next in while loop not honored
by GrandFather (Saint) on Nov 05, 2014 at 20:21 UTC

    If you are using explicit ranges like that then use for loops instead of while loops to make it clear that a range is being dealt with and what the range is. Consider:

    #!/usr/bin/perl use strict; use warnings; my $maxline = 5; my $start = 2; my $fileName = "testlog"; open my $info, '<', $fileName or die "Could not open '$fileName': $!"; <$info> // die "Log file '$fileName' too short\n" for 1 .. $start - 1; for ($start .. $maxline) { my $line = <$info> // die "Log file '$fileName' too short\n"; print $line; }

    The <$info> // die ... stuff dies on end of file.

    Perl is the programming world's equivalent of English
      thanks to all of you guys
Re: next in while loop not honored
by Laurent_R (Canon) on Nov 05, 2014 at 20:14 UTC
    Using the $. special variable is the easiest solution. And it is fine here, since you are planning to print only a few lines. But if the file you are reading is huge and just want to skip the first line, then it is faster to avoid making the test for every single line you are reading by removing the header line before entering the loop:
    # ... my $useless_line = <$info>; # reads the first line and throws it away while( my $line = <$info>) { print $line; last if $. >= $maxline; print "$. \n"; }

      The trivial time that may be saved due to removing a simple test is completely irrelevant. However there is a generally big gain in clarity by simplifying code. In that vein, my $useless_line = <$info>; should simply be <$info>; which is much better at conveying the idea that we really don't want to use the contents of the line just read.

      Perl is the programming world's equivalent of English
        I found time not so trivial when reading several files with 300 M + lines. It also makes the loop cleaner by removing from it things that don't need to be in it. It also make the algorithm slightly simpler when reading a sorted file to remove duplicates or reading in parallel two (or more) files sorted according to the same key to compare data.

        As for the my $useless_line = <$info>;, I would probably not really code it that way, but I thought giving such a name would make it more self-explanatory to the OP, you seem to disagree, maybe I was wrong, I don't know.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (3)
As of 2025-07-09 10:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.