This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1 TITLE

Angle brackets should accept filenames and lists

=head1 VERSION

  Maintainer: Jon Ericson <[EMAIL PROTECTED]>
  Date: 6 August 2000
  Version: 1
  Mailing List: [EMAIL PROTECTED]
  Number: 51

=head1 ABSTRACT

If the file-globbing behavior of angle brackets is
removed (RFC 34), enclosing a non-filehandle will be
undefined.  Perl should treat non-filehandles as
filenames and Do What I Mean.  Also, angle brackets
should should handle lists (of filenames and
filehandles).

=head1 DESCRIPTION

=head2 Background

>From perlop/"I/O Operators":

In scalar context, evaluating a filehandle in angle brackets yields
the next line from that file (the newline, if any, included), or
C<undef> at end-of-file or on error.  When C<$/> is set to C<undef>
(sometimes known as file-slurp mode) and the file is empty, it
returns C<''> the first time, followed by C<undef> subsequently.

[snipped use of angle brackets in a while loop and predefined filehandles]

If a <FILEHANDLE> is used in a context that is looking for
a list, a list comprising all input lines is returned, one line per
list element.  It's easy to grow to a rather large data space this
way, so use with care.

<FILEHANDLE> may also be spelled C<readline(*FILEHANDLE)>.
See L<perlfunc/readline>.

The null filehandle <> is special: it can be used to emulate the
behavior of B<sed> and B<awk>.  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, C<$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 I<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.)

You can modify @ARGV before the first <> as long as the array ends up
containing the list of filenames you really want. Line numbers (C<$.>)
continue as though the input were one big happy file. See the example
in L<perlfunc/eof> for how to reset line numbers on each file.

If you want to set @ARGV to your own list of files, go right ahead.
This sets @ARGV to all plain text files if no @ARGV was given:

    @ARGV = grep { -f && -T } glob('*') unless @ARGV;

You can even set them to pipe commands.  For example, this automatically
filters compressed arguments through B<gzip>:

    @ARGV = map { /\.(gz|Z)$/ ? "gzip -dc < $_ |" : $_
} @ARGV;

If you want to pass switches into your script, you can use one of the
Getopts modules or put a loop on the front like this:

    while ($_ = $ARGV[0], /^-/) {
        shift;
        last if /^--$/;
        if (/^-D(.*)/) { $debug = $1 }
        if (/^-v/)     { $verbose++  }
        # ...           # other switches
    }

    while (<>) {
        # ...           # code for each line
    }

The <> symbol will return C<undef> for end-of-file only once.
If you call it again after this, it will assume you are processing another
@ARGV list, and if you haven't set @ARGV, will read input from STDIN.

=head2 Easy things should be easy

Input from a file is already easy in Perl, but it
could be easier.

=head2 Flexibility

As noted above, the behavior this RFC proposes is
already partially availible with @ARGV and <>.  But
you can't mix filenames with filehandles.  Nor is it
obvious what you are doing.  And it takes two steps.

=head1 IMPLEMENTATION

Let:

    while (<LIST>) {
         # code for each line
    }

be "equivalent to the following Perl-like pseudo code":

    @ARGV = LIST;
    unshift(@ARGV, '-') unless @ARGV;
    while ($ARGV = shift) {
        my $fh;
        if (ref $ARGV eq 'GLOB'){ # or filehandle ref result
            $fh = $ARGV;
        }else{ # should we include other cases (e.g. array refs)?
            open($fh, $ARGV) or warn "can't open $ARGV: $!";
        };
        while (<$fh>) {
            # code for each line
        };
    };



=head1 REFERENCES

  RFC 34 - Angle brackets should not be used for file globbing.
  perlop/"I/O Operators"

Reply via email to