open RESULTS,"> runstats" or die "can't open runstats: $!";
open LOG, ">> logfile " or die "can't open logfile: $!";
-A few things to notice. First, the leading less-than is optional.
+A few things to notice. First, the leading C<< < >> is optional.
If omitted, Perl assumes that you want to open the file for reading.
Note also that the first example uses the C<||> logical operator, and the
which is definitely not what you want.
The other important thing to notice is that, just as in the shell,
-any white space before or after the filename is ignored. This is good,
+any whitespace before or after the filename is ignored. This is good,
because you wouldn't want these to do different things:
open INFO, "<datafile"
This is not a bug, but a feature. Because C<open> mimics the shell in
its style of using redirection arrows to specify how to open the file, it
-also does so with respect to extra white space around the filename itself
+also does so with respect to extra whitespace around the filename itself
as well. For accessing files with naughty names, see
L<"Dispelling the Dweomer">.
conflicts.
Another convenient behavior is that an indirect filehandle automatically
-closes when it goes out of scope or when you undefine it:
+closes when there are no more references to it:
sub firstline {
open( my $in, shift ) && return scalar <$in>;
# no close() required
}
+Indirect filehandles also make it easy to pass filehandles to and return
+filehandles from subroutines:
+
+ for my $file ( qw(this.conf that.conf) ) {
+ my $fin = open_or_throw('<', $file);
+ process_conf( $fin );
+ # no close() needed
+ }
+
+ use Carp;
+ sub open_or_throw {
+ my ($mode, $filename) = @_;
+ open my $h, $mode, $filename
+ or croak "Could not open '$filename': $!";
+ return $h;
+ }
+
=head2 Pipe Opens
In C, when you want to open a file using the standard I/O library,
library will handle this for you. Check out
L<perlipc/"Bidirectional Communication with Another Process">
+perl-5.6.x introduced a version of piped open that executes a process
+based on its command line arguments without relying on the shell. (Similar
+to the C<system(@LIST)> notation.) This is safer and faster than executing
+a single argument pipe-command, but does not allow special shell
+constructs. (It is also not supported on Microsoft Windows, Mac OS Classic
+or RISC OS.)
+
+Here's an example of C<open '-|'>, which prints a random Unix
+fortune cookie as uppercase:
+
+ my $collection = shift(@ARGV);
+ open my $fortune, '-|', 'fortune', $collection
+ or die "Could not find fortune - $!";
+ while (<$fortune>)
+ {
+ print uc($_);
+ }
+ close($fortune);
+
+And this C<open '|-'> pipes into lpr:
+
+ open my $printer, '|-', 'lpr', '-Plp1'
+ or die "can't run lpr: $!";
+ print {$printer} "stuff\n";
+ close($printer)
+ or die "can't close lpr: $!";
+
=head2 The Minus File
Again following the lead of the standard shell utilities, Perl's
open(WTMP, "+< /usr/adm/wtmp")
|| die "can't open /usr/adm/wtmp: $!";
- open(SCREEN, "+> /tmp/lkscreen")
- || die "can't open /tmp/lkscreen: $!";
+ open(SCREEN, "+> lkscreen")
+ || die "can't open lkscreen: $!";
- open(LOGFILE, "+>> /tmp/applog"
- || die "can't open /tmp/applog: $!";
+ open(LOGFILE, "+>> /var/log/applog")
+ || die "can't open /var/log/applog: $!";
The first one won't create a new file, and the second one will always
clobber an old one. The third one will create a new file if necessary
$ myprogram file1 file2 file3
-Can have all its files opened and processed one at a time
+can have all its files opened and processed one at a time
using a construct no more complex than:
while (<>) {
name into pipes. For example, to autoprocess gzipped or compressed
files by decompressing them with I<gzip>:
- @ARGV = map { /^\.(gz|Z)$/ ? "gzip -dc $_ |" : $_ } @ARGV;
+ @ARGV = map { /\.(gz|Z)$/ ? "gzip -dc $_ |" : $_ } @ARGV;
Or, if you have the I<GET> program installed from LWP,
you can fetch URLs before processing them:
The HANDLE argument is a filehandle just as with C<open>. The PATH is
a literal path, one that doesn't pay attention to any greater-thans or
-less-thans or pipes or minuses, nor ignore white space. If it's there,
+less-thans or pipes or minuses, nor ignore whitespace. If it's there,
it's part of the path. The FLAGS argument contains one or more values
derived from the Fcntl module that have been or'd together using the
bitwise "|" operator. The final argument, the MASK, is optional; if
Here's how to use C<sysopen> to emulate the simple C<open> calls we had
before. We'll omit the C<|| die $!> checks for clarity, but make sure
you always check the return values in real code. These aren't quite
-the same, since C<open> will trim leading and trailing white space,
+the same, since C<open> will trim leading and trailing whitespace,
but you'll get the idea.
To open a file for reading:
Why so permissive? Well, it isn't really. The MASK will be modified
by your process's current C<umask>. A umask is a number representing
I<disabled> permissions bits; that is, bits that will not be turned on
-in the created files' permissions field.
+in the created file's permissions field.
For example, if your C<umask> were 027, then the 020 part would
disable the group from writing, and the 007 part would disable others
"&" but rather with a "&=" combination, then Perl will not create a
completely new descriptor opened to the same place using the dup(2)
system call. Instead, it will just make something of an alias to the
-existing one using the fdopen(3S) library call This is slightly more
+existing one using the fdopen(3S) library call. This is slightly more
parsimonious of systems resources, although this is less a concern
these days. Here's an example of that:
NULs within a valid filename. Most systems follow these conventions,
including all POSIX systems as well as proprietary Microsoft systems.
The only vaguely popular system that doesn't work this way is the
-proprietary Macintosh system, which uses a colon where the rest of us
+"Classic" Macintosh system, which uses a colon where the rest of us
use a slash. Maybe C<sysopen> isn't such a bad idea after all.
If you want to use C<< <ARGV> >> processing in a totally boring
open(STDOUT, "> output")
|| die "can't open output: $!";
-And then these can be read directly or passed on to subprocesses.
+And then these can be accessed directly or passed on to subprocesses.
This makes it look as though the program were initially invoked
with those redirections from the command line.
sub head {
my $lines = shift || 20;
- return unless $pid = open(STDOUT, "|-");
+ return if $pid = open(STDOUT, "|-"); # return if parent
die "cannot fork: $!" unless defined $pid;
while (<STDIN>) {
- print;
last if --$lines < 0;
+ print;
}
exit;
}
sockets, you can set them to be non-blocking using C<fcntl>:
use Fcntl;
- fcntl(Connection, F_SETFL, O_NONBLOCK)
+ my $old_flags = fcntl($handle, F_GETFL, 0)
+ or die "can't get flags: $!";
+ fcntl($handle, F_SETFL, $old_flags | O_NONBLOCK)
or die "can't set non blocking: $!";
Rather than losing yourself in a morass of twisting, turning C<ioctl>s,
it's still easy to get the contents of a document:
use LWP::Simple;
- $doc = get('http://www.linpro.no/lwp/');
+ $doc = get('http://www.cpan.org/');
=head2 Binary Files
C<< '<' >>, C<< '>' >>, C<< '>>' >>, C<< '|' >> and their variants,
for example:
- open(my $fh, "<:utf8", $fn);
+ open(my $fh, "<:crlf", $fn);
=item *
=back
-For more detailed discussion about PerlIO see L<perlio>;
+For more detailed discussion about PerlIO see L<PerlIO>;
for more detailed discussion about Unicode and I/O see L<perluniintro>.
=head1 SEE ALSO