Search code examples
perlfile-ioseek

How can I reset a file handle receiving standard input in Perl?


When I issue a Perl script some standard input, e.g.

$ awk '{print $1"\t"$2}' foo.txt | myScript.pl

I have a script which contains a bug. It reads the first line of standard input, gets something from that first line, and then only parses lines 2 through n of standard input on subsequent read:

open (FH, "< $input") or die $?;
my $firstLine = <FH>; // reads first line

...

while (my $line = <FH>) {
    // reads lines 2 through n
}
close (FH);

So I added a seek statement to this script to try to reset the file handle to the beginning of the file:

use Fcntl qw(:seek);

...

open (FH, "< $input") or die $?;
my $firstLine = <FH>; // reads first line
seek (FH, 0, SEEK_SET) or die "error: could not reset file handle\n"; // should reset file handle

...

while (my $line = <FH>) {
    // reads lines 1 through n (in theory)
}
close (FH);

Adding this seek statement works for file input, but not for standard input. The script crashes with the error:

 error: could not reset file handle 

How can I correctly read the first line of standard input at the start of the script, reset the file handle and then read all lines 1 through n of the standard input?

I guess I can write a special case for storing and processing the first line before the while loop, but I'm hoping there is a cleaner solution to this problem that allows me to handle both standard input and file input.


Solution

  • There's an easy way:

    open (FH, "< $input") or die $?;
    my $line = <FH>; # reads first line
    
    # do stuff with first line
    
    do {
        # stuff
    } while ($line = <FH>);