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

One idiom I sometimes use (in quick one-off scripts) for reading a file is `cat ...`, like this:

frobnicate( $_ ) for `cat foobar.txt`;
but it has the drawback that the entire file is read into a list before it is processed, which can be a problem for large files. It would be better to use a while loop that reads and processes one line at a time, but the best while idiom I've been able to come up with is
{ local @ARGV = 'foobar.txt'; frobnicate( $_ ) while <>; }
which is a bit long, and relies on the @ARGV hack. Is there something more succinct and/or less klugey?

Update: From the responses I realize that I should have been clearer about noting that there are some special cases for which I already know fine idioms. For example, if the filename is given to the script via @ARGV, then it's hard to beat something as simple as

frobnicate( $_ ) while <>;
Similarly, if all the script does is process lines from one or more input files, then
#!perl -n frobnicate( $_ );
is plenty simple.

The situation that I was referring to is the more general one in which the filename is obtained in some way other than via @ARGV, and the script does more than process lines read from input files (in which case -n less convenient). In fact, most of the scripts I work on are too long to be suitable for the command line.

the lowliest monk

Replies are listed 'Best First'.
Re: Idle search for a file-read idiom
by davido (Cardinal) on Apr 22, 2005 at 15:38 UTC

    The standard idiom is a little longer:

    open FH, '<', 'foobar.txt' or die "Bleah!\n$!"; frobnicate( $_ ) while <FH>; close FH;

    If $fh is declared within a narrow lexical scope you don't have to worry about closing the filehandle; it will close when it falls out of scope:

    { open my $fh, '<', 'foobar.txt' or die $!; frobnicate( $_ ) while <$fh>; }

    Dave

Re: Idle search for a file-read idiom
by revdiablo (Prior) on Apr 22, 2005 at 16:28 UTC
    Is there something more succinct and/or less klugey?

    In terms of straight Perl, I think you've pretty much got it. The "@ARGV hack", as you call it, is a standard slurp idiom. I agree that it's not pretty, but it works most of the time. When it fails, the standard open constructs aren't that bad.

    But if you really want to do some slick IO with a small amount of work, take a look at IO::All. There are so many cool things it can do, with such a small amount of effort, that I'm not even going to try to summarize them. Just check it out. :-)

Re: Idle search for a file-read idiom
by starbolin (Hermit) on Apr 22, 2005 at 15:51 UTC

    perl -ne 'frobinate( $_) ' foobar.txt

    or am I missing some constraint you have?

    s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}

      Oh, you say you want a longer script. Like from a file.

      #!/usr/bin/perl -wn BEGIN{$num=0}; print ++$num,' ',$_; END{print "\nDo some processing outside of the loop.\n"}

      Prints the file on the command line with linenumbers added and prints a summary.

      s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}
Re: Idle search for a file-read idiom
by 5mi11er (Deacon) on Apr 22, 2005 at 15:41 UTC
    Am I missing something? I'd suggest:
    while (<>) { frobnicate($_); }
    Run it with "$0 foobar.txt"

    -Scott

      You're assuming that @ARGV contains only the file name. This solution is what tlm suggests to use as an alternative to his quick hack, but he has to set @ARGV first.

      Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

      Don't fool yourself.