Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

seek question

by natxo (Scribe)
on Feb 09, 2017 at 20:38 UTC ( [id://1181584]=perlquestion: print w/replies, xml ) Need Help??

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

I want to print the first 3 lines of a file. This works:
my $f = "/etc/fstab"; open ( my $fh, "<", $f ); while ( <$fh> ) { print if (1..3) ; }
But if I print everything, rewind the file to the beginning, and print the first three lines again, it does not work:
my $f = "/etc/fstab"; open ( my $fh, "<", $f ); while ( <$fh> ) { chomp; print "$_\n"; } print "=" x 78, "\n\n"; print "after 1st while loop\n"; seek( $fh, 0, 0); while ( <$fh> ) { print if (1..3) ; }
using warnings, strict, autodie (implicit in the code).

I can solve it using a counter inside the latest while loop, but I am just curious why it does not work as expected. Thanks for any insights.

Replies are listed 'Best First'.
Re: seek question
by toolic (Bishop) on Feb 09, 2017 at 20:56 UTC
      thanks for spotting my copy/paste error. It's corrected now. And for pointing me in the correct direction, of course.
Re: seek question
by choroba (Cardinal) on Feb 09, 2017 at 21:02 UTC

      oooh, I like the inline method of resetting $. that you provided in that thread:

      seek $FH, $. = 0, 0;

        Keep in mind though that the seek will fail for streams, named pipes and the like. (/me's thinking of all the kludgy softwares out there e.g. mplayer that couldn't properly read a playlist from a pipe.)

Re: seek question
by stevieb (Canon) on Feb 09, 2017 at 21:01 UTC

    I can't say I've ever run across an if() statement used as such, I assume that it's doing a if ($. == 1) from 1 to 3 implicitly, but I'm unsure.

    One thing I do know is that seek does not reset the line number variable $. when positioning back to the beginning of the file, so you have to set it explicitly:

    use warnings; use strict; my $f = "/etc/fstab"; open ( my $fh, "<", $f ); while ( <$fh> ) { print "$.: $_"; } print "=" x 78, "\n\n"; print "after 1st while loop\n"; seek( $fh, 0, 0); # reset line num $. = 0; while ( <$fh> ) { print if (1..3); }

      G'day stevieb,

      OP wrote:

      "... if (1..3) ..."

      You wrote:

      "I can't say I've ever run across an if() statement used as such, I assume that it's doing a if ($. == 1) from 1 to 3 implicitly, but I'm unsure."

      From "perlop: Range Operators":

      "If either operand of scalar ".." is a constant expression, that operand is considered true if it is equal (==) to the current input line number (the $. variable)."

      — Ken

      The seek() function deals with bytes. It knows nothing at all about "lines" or line numbers.

      Of course in this case, you could close the file and then re-open it to reset the $. line counter. I've never had to do that, but it would work.

        I understand that, but OP was looping over the file handle which does use $.. I just meant that seek() does not reset this when going back to first row, first column, so that has to be done manually.

        I concur that closing/re-opening the handle would have the same effect as $. = 0;.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (2)
As of 2024-04-26 04:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found