RFC 51 (v1) Angle brackets should accept filenames a
[email protected] (Perl6 RFC Librarian) 6 Aug 2000 23:39:21 -0000
| Newsgroups | perl.perl6.language.io |
|---|---|
| Message-ID | <[email protected]> |
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"