xoxo,
Andy
diff -ruN bleadperl/pod/perlopentut.pod bleadpatch/pod/perlopentut.pod
--- bleadperl/pod/perlopentut.pod Wed Jun 12 19:02:45 2002
+++ bleadpatch/pod/perlopentut.pod Thu Sep 19 22:18:22 2002
@@ -5,7 +5,9 @@
=head1 DESCRIPTION
Perl has two simple, built-in ways to open files: the shell way for
-convenience, and the C way for precision. The choice is yours.
+convenience, and the C way for precision. The shell way also has 2- and
+3-argument forms, which have different semantics for handling the filename.
+The choice is yours.
=head1 Open E<agrave> la shell
@@ -36,7 +38,7 @@
The C<open> function takes two arguments: the first is a filehandle,
and the second is a single string comprising both what to open and how
to open it. C<open> returns true when it works, and when it fails,
-returns a false value and sets the special variable $! to reflect
+returns a false value and sets the special variable C<$!> to reflect
the system error. If the filehandle was previously opened, it will
be implicitly closed first.
@@ -56,6 +58,14 @@
A few things to notice. First, the leading less-than 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
+second uses C<or>, which has lower precedence. Using C<||> in the latter
+examples would effectively mean
+
+ open INFO, ( "< datafile" || die "can't open datafile: $!" );
+
+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,
because you wouldn't want these to do different things:
@@ -76,6 +86,41 @@
as well. For accessing files with naughty names, see
L<"Dispelling the Dweomer">.
+There is also a 3-argument version of C<open>, which lets you put the
+redirection special characters into their own argument.
+
+ open( INFO, ">", $datafile ) || die "Can't create $datafile: $!";
+
+Here, you don't have to worry about C<$datafile> containing characters
+that might influence the open mode, or whitespace at the beginning of
+the filename that would be absorbed in the 2-argument version. Plus,
+any reduction of unnecessary string interpolation is a good thing.
+
+=head2 Indirect Filehandles
+
+C<open>'s first argument can be a reference to a filehandle. If the
+argument is uninitialized, Perl will automatically create a filehandle
+and put a reference to it in the first argument, like so:
+
+ open( my $in, $infile ) or die "Couldn't read $infile: $!";
+ while ( <$in> ) {
+ # do something with $_
+ }
+ close $in;
+
+Indirect filehandles make namespace management easier. Since filehandles
+are global to the current package, two subroutines trying to open
+C<INFILE> will clash. With two functions opening indirect filehandles
+like C<my $infile>, there's no clash and no need to worry about future
+conflicts.
+
+Another convenient behavior is how an indirect filehandle automatically
+closes when it goes out of scope or when you undefine it.
+
+ sub firstline {
+ open( my $in, shift ) && return <$in>; # no close() required
+ }
+
=head2 Pipe Opens
In C, when you want to open a file using the standard I/O library,
@@ -85,7 +130,7 @@
remains the same--just its argument differs.
If the leading character is a pipe symbol, C<open> starts up a new
-command and open a write-only filehandle leading into that command.
+command and opens a write-only filehandle leading into that command.
This lets you write into that handle and have what you write show up on
that command's standard input. For example:
@@ -98,7 +143,7 @@
command writes to its standard output show up on your handle for reading.
For example:
- open(NET, "netstat -i -n |") || die "can't fun netstat: $!";
+ open(NET, "netstat -i -n |") || die "can't open netstat: $!";
while (<NET>) { } # do something with input
close(NET) || die "can't close netstat: $!";
@@ -252,8 +297,8 @@
Yes, this also means that if you have a file named "-" (and so on) in
your directory, that they won't be processed as literal files by C<open>.
-You'll need to pass them as "./-" much as you would for the I<rm> program.
-Or you could use C<sysopen> as described below.
+You'll need to pass them as "./-", much as you would for the I<rm> program,
+or you could use C<sysopen> as described below.
One of the more interesting applications is to change files of a certain
name into pipes. For example, to autoprocess gzipped or compressed
@@ -310,7 +355,7 @@
C<O_DEFER>, C<O_SYNC>, C<O_ASYNC>, C<O_DSYNC>, C<O_RSYNC>,
C<O_NOCTTY>, C<O_NDELAY> and C<O_LARGEFILE>. Consult your open(2)
manpage or its local equivalent for details. (Note: starting from
-Perl release 5.6 the O_LARGEFILE flag, if available, is automatically
+Perl release 5.6 the C<O_LARGEFILE> flag, if available, is automatically
added to the sysopen() flags because large files are the default.)
Here's how to use C<sysopen> to emulate the simple C<open> calls we had
@@ -503,7 +548,7 @@
That's because you opened a filehandle FH, and had read in seven records
from it. But what was the name of the file, not the handle?
-If you aren't running with C<strict refs>, or if you've turn them off
+If you aren't running with C<strict refs>, or if you've turned them off
temporarily, then all you have to do is this:
open($path, "< $path") || die "can't open $path: $!";
@@ -622,8 +667,8 @@
closedir(DIR);
If you want to process directories recursively, it's better to use the
-File::Find module. For example, this prints out all files recursively,
-add adds a slash to their names if the file is a directory.
+File::Find module. For example, this prints out all files recursively
+and adds a slash to their names if the file is a directory.
@ARGV = qw(.) unless @ARGV;
use File::Find;
@@ -645,6 +690,8 @@
}
}
+=head2 Opening Named Pipes
+
Named pipes are a different matter. You pretend they're regular files,
but their opens will normally block until there is both a reader and
a writer. You can read more about them in L<perlipc/"Named Pipes">.
@@ -685,6 +732,8 @@
also some high-level modules on CPAN that can help you with these games.
Check out Term::ReadKey and Term::ReadLine.
+=head2 Opening Sockets
+
What else can you open? To open a connection using sockets, you won't use
one of Perl's two open functions. See
L<perlipc/"Sockets: Client/Server Communication"> for that. Here's an
@@ -752,11 +801,13 @@
Never use the existence of a file C<-e $file> as a locking indication,
because there is a race condition between the test for the existence of
-the file and its creation. Atomicity is critical.
+the file and its creation. It's possible for another process to create
+a file in the slice of time between your existence check and attempt to
+create the file. Atomicity is critical.
Perl's most portable locking interface is via the C<flock> function,
whose simplicity is emulated on systems that don't directly support it,
-such as SysV or WindowsNT. The underlying semantics may affect how
+such as SysV or Windows. The underlying semantics may affect how
it all works, so you should learn how C<flock> is implemented on your
system's port of Perl.
@@ -814,9 +865,8 @@
or die "can't truncate filename: $!";
# now write to FH
-Finally, due to the uncounted millions who cannot be dissuaded from
-wasting cycles on useless vanity devices called hit counters, here's
-how to increment a number in a file safely:
+Here's an example of safely incrementing a number in a file, as you
+might for a web page hit counter:
use Fcntl qw(:DEFAULT :flock);
@@ -856,7 +906,7 @@
=item *
-The three-(or more)-argument form of C<open()> is being used and the
+The three-(or more)-argument form of C<open> is being used and the
second argument contains something else in addition to the usual
C<< '<' >>, C<< '>' >>, C<< '>>' >>, C<< '|' >> and their variants,
for example:
@@ -865,7 +915,7 @@
=item *
-The two-argument form of C<binmode<open()> is being used, for example
+The two-argument form of C<binmode> is being used, for example
binmode($fh, ":encoding(utf16)");
--
'Andy Lester an...@petdance.com
Programmer/author petdance.com
Daddy parsley.org/quinn Jk'=~/.+/s;print((split//,$&)
[unpack'C*',"n2]3%+>\"34.'%&.'^%4+!o.'"])
Make that "return scalar <$in>;"
> - open(NET, "netstat -i -n |") || die "can't fun netstat: $!";
> + open(NET, "netstat -i -n |") || die "can't open netstat: $!";
That should read "can't fork netstat" to be totally correct.
> while (<NET>) { } # do something with input
> close(NET) || die "can't close netstat: $!";
Isn't it overly paranoid to check for errors on close()?
Just my EUR 0.02
Roland
--
RGie...@cpan.org
Not even for files. For example if you've written to an NFS file
and there's an error on the server (eg disk full), you may not be notified
until you do the close() system call due to buffering and delayed writes
etc.
(We found this out with the compress(1) command baCk on SunOs 4.x -
typically a student would go over quota, run compress(1) on some of their
files, and compress(1) would silently truncate them to zero length. So we
politely asked Sun to make their utilites check the close(2) status.
--
"Strange women lying in ponds distributing swords is no basis for a system
of government. Supreme executive power derives from a mandate from the
masses, not from some farcical aquatic ceremony."
Dennis - Monty Python and the Holy Grail.
For files, yes, for pipes, no.
perldoc -f close
...
If the file handle came from a piped open C<close()> will additionally
return FALSE if one of the other system calls involved fails or if the
program exits with non-zero status.
Ronald
Duh. Thanks.
> That should read "can't fork netstat" to be totally correct.
Agreed. Fixed.
> Isn't it overly paranoid to check for errors on close()?
Perhaps, but I didn't want to change any more of the original than
necessary.
This patch is meant to introduce the new 3-argument version of open, not
gut the entire tutorial which is pretty solid as it is. I tried to make
changes as surgical as possible.
I'd like to either get a yea or nay from Hugo, get the thing applied,
and then we can worry about the massive rewrite that's being suggested.
xoxo,
Andy
For read perhaps - but not for write with buffered IO and files < buffer
size the _only_ error you may get from system will be on the close().
>
>Just my EUR 0.02
>
>Roland
--
Nick Ing-Simmons
http://www.ni-s.u-net.com/
I haven't had a chance to sit down and read through it; I'm happy for
Rafael or Abhijit to apply as is for now, if you need a stable point
to make further changes from. Failing that, I'll get to it in a few days,
when I'm back in the UK and somewhat recovered from YAPC.
Hugo
It's not that I need a stable base so much as that the suggestions of
"redo the whole thing" are outside the scope of the patch that I'm
submitting. My patch is still an improvement, if not the revamp that
might be an even bigger one.
xoa
I'm not so sure.
This used to be:
open(NET, "netstat -i -n |") || die "cannot fork: $!";
But it was changed (along with the following paragraph) to
demonstrate that you can get the error from a failed exec()
as well.
How about "can't run netstat: $!" ? It's vague enough to
cover both possibilities, and presumably what the last patch
intended.
--
Steve
perldoc -qa.j | perl -lpe '($_)=m("(.*)")'
Very good observation. Seems like a patch to the perlfunc close() docs
is in order...
> (We found this out with the compress(1) command baCk on SunOs 4.x -
> typically a student would go over quota, run compress(1) on some of
> their files, and compress(1) would silently truncate them to zero
> length. So we politely asked Sun to make their utilites check
> the close(2) status.
Ugh! And, did they comply? Seems like an awful gotcha to me... :-)
Roland
--
RGie...@cpan.org
Well, they fixed compress, but I doubt that they fixed the other
utilities. I don't know the state of play in SolarisN for N >= 2.
--
A walk of a thousand miles begins with a single step...
then continues for another 1,999,999 or so.
They started fixing lots of them around 2.4 time I believe. IIRC lack of
checking close() was the cause of Liverpool University doing an emergency
downgrade from Solaris 2.4 back to 2.3 - 2.4's multithreading NFS meant that
write no longer failed on quota limits; instead the error was reported at
close time, which meant that many file writing failures were no longer
spotted. As soon as the University sysadmins realised this they dropped back,
until they had a work around. (An annoying background program that spammed
all your logged in terminals with write every time it noticed that you touched
your soft quota)
Moral: Always check close.
(and if I find that someone is not, *I* certainly won't be buying software
from them. Although my "budget" means I'm hardly a measurable economic
influence.
And I believe that Sun has now fixed these things some years ago, so I can
buy Solaris without being hypocritical. I like Solaris - I find it hard to
crash. And Sun gave cpan.org hardware, which is nice)
Nicholas Clark
--
Even better than the real thing: http://nms-cgi.sourceforge.net/