atom feed54 messages in org.perl.perl5-porters[PATCH] [DOCS] Modernize perlopentut.pod
FromSent OnAttachments
Mike DohertyJul 15, 2011 8:31 pm.patch
Tom ChristiansenJul 15, 2011 9:38 pm 
Tom ChristiansenJul 15, 2011 9:52 pm 
Ricardo SignesJul 16, 2011 5:12 am 
Richard FoleyJul 16, 2011 6:20 am 
Tom ChristiansenJul 16, 2011 9:31 am 
Andrew RodlandJul 16, 2011 5:04 pm 
Matt S TroutJul 17, 2011 2:39 am 
Christian WaldeJul 17, 2011 3:38 am 
Marvin HumphreyJul 17, 2011 5:24 am 
Johan VromansJul 17, 2011 7:18 am 
ZeframJul 17, 2011 7:48 am 
Leon TimmermansJul 18, 2011 6:13 am 
Matt S TroutJul 18, 2011 8:07 am 
demerphqJul 18, 2011 8:24 am 
Mike DohertyJul 18, 2011 1:16 pm 
David GoldenJul 18, 2011 1:36 pm 
Greg LindahlJul 18, 2011 2:01 pm 
Aristotle PagaltzisJul 19, 2011 7:38 pm 
David GoldenJul 19, 2011 8:14 pm 
George GreerJul 19, 2011 8:31 pm 
Jesse LuehrsJul 19, 2011 8:40 pm 
AbigailJul 19, 2011 10:56 pm 
Tom ChristiansenJul 19, 2011 11:52 pm 
Tom ChristiansenJul 19, 2011 11:54 pm 
Christian WaldeJul 20, 2011 1:21 am 
Dagfinn Ilmari MannsåkerJul 20, 2011 1:33 am 
Ed AvisJul 20, 2011 5:03 am 
AbigailJul 20, 2011 5:19 am 
Offer KayeJul 20, 2011 5:59 am 
David GoldenJul 20, 2011 6:39 am 
Aristotle PagaltzisJul 20, 2011 7:55 am 
Aristotle PagaltzisJul 20, 2011 8:05 am 
David GoldenJul 20, 2011 8:27 am 
Karl WilliamsonJul 20, 2011 9:10 am 
Jesse VincentJul 20, 2011 10:28 am 
Mike DohertyJul 20, 2011 1:04 pm 
Jesse VincentJul 20, 2011 1:10 pm 
Dave RolskyJul 20, 2011 1:14 pm 
Jesse LuehrsJul 20, 2011 1:35 pm 
Mike DohertyJul 20, 2011 1:56 pm 
Johan VromansJul 20, 2011 2:56 pm 
Jesse LuehrsJul 20, 2011 3:04 pm 
Mike DohertyJul 20, 2011 3:31 pm 
Aristotle PagaltzisJul 20, 2011 11:36 pm 
Ed AvisJul 21, 2011 5:16 am 
Matt S TroutJul 23, 2011 12:54 am 
AbigailJul 23, 2011 2:31 am 
Nathaniel R. ReindlJul 23, 2011 3:37 am 
Matt S TroutJul 23, 2011 4:49 am 
Johan VromansJul 23, 2011 5:59 am 
Aristotle PagaltzisJul 23, 2011 8:03 am 
Christian WaldeJul 23, 2011 8:09 am 
Father ChrysostomosJul 24, 2011 12:32 pm 
Subject:[PATCH] [DOCS] Modernize perlopentut.pod
From:Mike Doherty (dohe@cs.dal.ca)
Date:Jul 15, 2011 8:31:13 pm
List:org.perl.perl5-porters
Attachments:

Hello,

Despite being a tutorial, perlopentut didn't seem to me to provide good advice. It predominantly used bareword filehandles and two-arg open, while current best practices call for lexical filehandles and three-arg open. With Matt Trout's encouragement, I've revised the tutorial slightly along those lines. I've added some terminology, rearranged sections, and mentioned autodie.

I was under the impression that submissions to perlbug were also sent to p5p, but I guess that was mistaken. So, here's the patch I submitted there: https://rt.perl.org/rt3/Ticket/Display.html?id=94860, on the assumption someone here will have something to say about it.

Thanks, -Mike Doherty

From 3665a39ada1398d26d1c17d405a50754078ff221 Mon Sep 17 00:00:00 2001 From: Mike Doherty <dohe@cs.dal.ca> Date: Sat, 9 Jul 2011 19:12:22 -0300 Subject: [PATCH] [DOCS] Modernize perlopentut.pod

This revises and rearranges perlopentut.pod to reflect more modern usages of open. In particular, it emphasisizes the use of 3-arg open over 2-arg, and the use of lexical filehandles (including an explanation of terminology). It also cleans up quoting and trailing whitespace, so you may wish to use -w to reduce the number of changes you see.

Thanks to Matt Trout for his encouragement.

--- pod/perlopentut.pod | 339 +++++++++++++++++++++++++++------------------------ 1 files changed, 181 insertions(+), 158 deletions(-)

diff --git a/pod/perlopentut.pod b/pod/perlopentut.pod index 4bb43bf..04b4f20 100644 --- a/pod/perlopentut.pod +++ b/pod/perlopentut.pod @@ -7,7 +7,7 @@ perlopentut - tutorial on opening things in Perl Perl has two simple, built-in ways to open files: the shell way for 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. +You'll probably want to use the 3-argument form.

=head1 Open E<agrave> la shell

@@ -19,7 +19,7 @@ from the shell: $ myprogram < inputfile $ myprogram > outputfile $ myprogram >> outputfile - $ myprogram | otherprogram + $ myprogram | otherprogram $ otherprogram | myprogram

And here are some more advanced examples: @@ -35,97 +35,54 @@ virtually the same syntax as the shell.

=head2 Simple Opens

-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 C<$!> to reflect -the system error. If the filehandle was previously opened, it will -be implicitly closed first. +The C<open> function takes three arguments: the first is a filehandle, +or a reference to a filehandle (which is preferred); the second is a +string specifying how to open the file (for reading, writing, appending, +etc.); the third is what file to open. Since Perl 5.6, if the argument +specifying the filehandle is undefined, then Perl will create a +filehandle, and put a reference to it into that argument. This is called +a "lexical" ("my") or "indirect" filehandle. We'll call it "lexical" here.

-For example: - - open(INFO, "datafile") || die("can't open datafile: $!"); - open(INFO, "< datafile") || die("can't open datafile: $!"); - open(RESULTS,"> runstats") || die("can't open runstats: $!"); - open(LOG, ">> logfile ") || die("can't open logfile: $!"); - -If you prefer the low-punctuation version, you could write that this way: - - open INFO, "< datafile" or die "can't open datafile: $!"; - 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 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 -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 whitespace before or after the filename is ignored. This is good, -because you wouldn't want these to do different things: - - open INFO, "<datafile" - open INFO, "< datafile" - open INFO, "< datafile" - -Ignoring surrounding whitespace also helps for when you read a filename -in from a different file, and forget to trim it before opening: +C<open> returns true when it works, and when it fails, returns a false +value and sets the special variable C<$!> to reflect the system error. +You can use the L<autodie> pragma to make it die with an exception, +if you prefer to avoid writing repetitive error-handling code yourself.

- $filename = <INFO>; # oops, \n still there - open(EXTRA, "< $filename") || die "can't open $filename: $!"; +If the filehandle was previously opened, it will be implicitly closed +first. This allows you to re-use the same reference rather than create +a new one for every filehandle you require.

-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 whitespace around the filename itself -as well. For accessing files with naughty names, see -L<"Dispelling the Dweomer">. +Here are some examples of the 3-argument form of open:

-There is also a 3-argument version of C<open>, which lets you put the -special redirection characters into their own argument: + open(my $info, '<', 'datafile') || die("Can't open datafile: $!"); + open(my $results, '>', 'runstats') || die("Can't open runstats: $!"); + open(my $log, '>>', 'logfile') || die("Can't open logfile: $!");

- open( INFO, ">", $datafile ) || die "Can't create $datafile: $!"; - -In this case, the filename to open is the actual string in C<$datafile>, -so 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. Also, -any reduction of unnecessary string interpolation is a good thing. +If you prefer the low-punctuation version, you could write that this way:

-=head2 Indirect Filehandles + open my $info, '<', 'datafile' or die "Can't open datafile: $!"; + open my $results, '>', 'runstats' or die "Can't open runstats: $!"; + open my $log, '>>', 'logfile' or die "Can't open logfile: $!";

-C<open>'s first argument can be a reference to a filehandle. As of -perl 5.6.0, if the argument is uninitialized, Perl will automatically -create a filehandle and put a reference to it in the first argument, -like so: +A few things to notice. 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( my $in, $infile ) or die "Couldn't read $infile: $!"; - while ( <$in> ) { - # do something with $_ - } - close $in; + open my $info, ( '<', 'datafile' || die "Can't open datafile: $!" );

-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. +which is definitely not what you want.

-Another convenient behavior is that an indirect filehandle automatically -closes when there are no more references to it: +When the filehandle is specified as a reference, it is a "lexical" filehandle, +which is automatically closed when there are no more references to it:

sub firstline { - open( my $in, shift ) && return scalar <$in>; - # no close() required + 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: +Lexical filehandles also make it easy to pass filehandles info subroutines, or +return a filehandle from a subroutine--just pass the reference like any other +reference:

for my $file ( qw(this.conf that.conf) ) { my $fin = open_or_throw('<', $file); @@ -141,31 +98,92 @@ filehandles from subroutines: return $h; }

+=head2 Bareword Filehandles + +C<open>'s first argument is normally a reference to a filehandle (a "lexical" +filehandle), making namespace management easier: + + open my $fh, '<', 'filename' or die "Couldn't open filename: $!"; + while (<$fh>) {...} # $fh is called "lexical" ("my") or "indirect" + +There is another way of specifying filehandles directly--"bareword"
filehandles: + + open INFO, '<', 'datafile' or die "Couldn't open datafile: $!"; + while (<INFO>) {...} # INFO is called "bareword", "direct", or "global" + +Since bareword filehandles are global to the current package, two subroutines +trying to open C<INFILE> will clash. With two functions opening lexical +filehandles like C<my $infile>, there's no clash and no need to worry about +future conflicts. Lexical filehandles are also automatically closed when they +fall out of scope in the same way that lexical variables are garbage-collected. + +Bareword filehandles are often used to refer to the standard input (C<*STDIN>), +output (C<*STDOUT>), and error filehandles (C<*STDERR>), but you can use +them for any filehandle if you wish. + +=head2 Two-Argument Open + +There is also an old 2-argument version of C<open>, which lets you put the +special redirection characters and the filename into the same argument: + + open(my $info, "> $datafile" ) || die "Can't create $datafile: $!"; + +In this case, the filename to open is not a separate argument, so +you have to worry about C<$datafile> containing characters that might +influence the open mode, or whitespace in the second argument that wouldn't +be a problem in the 3-argument version. + +Another important thing to notice is that, just as in the shell, any whitespace +before or after the filename is ignored. This is good, because you wouldn't +want these to do different things: + + open my $info, '<datafile' + open my $info, '< datafile' + open my $info, '< datafile' + +Ignoring surrounding whitespace also helps for when you read a filename in from +a different file, and forget to trim it before opening: + + $filename = <$info>; # oops, \n still there + open(my $extra, "< $filename") || die "can't open $filename: $!"; + +This is a feature, not a bug. 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 whitespace around the filename itself as well. For accessing +files with naughty names, see L<"Dispelling the Dweomer">. + +When opening a file, the leading C<< < >> is optional. If omitted, Perl assumes +that you want to open the file for reading: + + open(my $info, $datafile) || die("Can't open $datafile: $!"); + =head2 Pipe Opens

In C, when you want to open a file using the standard I/O library, you use the C<fopen> function, but when opening a pipe, you use the C<popen> function. But in the shell, you just use a different redirection -character. That's also the case for Perl. The C<open> call -remains the same--just its argument differs. +character. That's also the case for Perl. The C<open> call +remains the same--just its argument differs.

If the leading character is a pipe symbol, C<open> starts up a new 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:

- open(PRINTER, "| lpr -Plp1") || die "can't run lpr: $!"; - print PRINTER "stuff\n"; - close(PRINTER) || die "can't close lpr: $!"; + open(my $printer, '| lpr -Plp1') || die "can't run lpr: $!"; + print $printer "stuff\n"; + close($printer) || die "can't close lpr: $!";

If the trailing character is a pipe, you start up a new command and open a read-only filehandle leading out of that command. This lets whatever that command writes to its standard output show up on your handle for reading. For example:

- open(NET, "netstat -i -n |") || die "can't fork netstat: $!"; - while (<NET>) { } # do something with input - close(NET) || die "can't close netstat: $!"; + open(my $net, 'netstat -i -n |') || die "can't fork netstat: $!"; + while (<$net>) { + # do something with input + } + close($net) || die "can't close netstat: $!";

What happens if you try to open a pipe to or from a non-existent command? If possible, Perl will detect the failure and set C<$!> as @@ -178,8 +196,8 @@ failure if Perl can't even run the shell. See
L<perlfaq8/"How can I capture STDERR from an external command?"> to see how to cope with this. There's also an explanation in L<perlipc>.

-If you would like to open a bidirectional pipe, the IPC::Open2 -library will handle this for you. Check out +If you would like to open a bidirectional pipe, the L<IPC::Open2> +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 @@ -220,7 +238,7 @@ access the standard output. If minus can be used as the default input or default output, what happens if you open a pipe into or out of minus? What's the default command it would run? The same script as you're currently running! This is actually -a stealth C<fork> hidden inside an C<open> call. See +a stealth C<fork> hidden inside an C<open> call. See L<perlipc/"Safe Pipe Opens"> for details.

=head2 Mixing Reads and Writes @@ -233,13 +251,13 @@ existing one. On the other hand, using a greater-than
always clobbers if there isn't an old one. Adding a "+" for read-write doesn't affect whether it only works on existing files or always clobbers existing ones.

- open(WTMP, "+< /usr/adm/wtmp") + open(my $wtmp, '+< /usr/adm/wtmp') || die "can't open /usr/adm/wtmp: $!";

- open(SCREEN, "+> lkscreen") + open(my $screen, '+> lkscreen') || die "can't open lkscreen: $!";

- open(LOGFILE, "+>> /var/log/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 @@ -262,14 +280,14 @@ on the end: $ perl -i.orig -pe 's/\bfoo\b/bar/g' *.[Cchy]

This is a short cut for some renaming games that are really -the best way to update textfiles. See the second question in +the best way to update textfiles. See the second question in L<perlfaq5> for more details.

-=head2 Filters +=head2 Filters

One of the most common uses for C<open> is one you never even notice. When you process the ARGV filehandle using -C<< <ARGV> >>, Perl actually does an implicit open +C<< <ARGV> >>, Perl actually does an implicit open on each file in @ARGV. Thus a program called like this:

$ myprogram file1 file2 file3 @@ -279,7 +297,7 @@ using a construct no more complex than:

while (<>) { # do something with $_ - } + }

If @ARGV is empty when the loop first begins, Perl pretends you've opened up minus, that is, the standard input. In fact, $ARGV, the currently @@ -294,17 +312,17 @@ simple ones by hand, the Getopts modules are good for
this: use Getopt::Std;

# -v, -D, -o ARG, sets $opt_v, $opt_D, $opt_o - getopts("vDo:"); + getopts('vDo:');

# -v, -D, -o ARG, sets $args{v}, $args{D}, $args{o} - getopts("vDo:", \%args); + getopts('vDo:', \%args);

Or the standard Getopt::Long module to permit named arguments:

use Getopt::Long; - GetOptions( "verbose" => \$verbose, # --verbose - "Debug" => \$debug, # --Debug - "output=s" => \$output ); + GetOptions( 'verbose' => \$verbose, # --verbose + 'Debug' => \$debug, # --Debug + 'output=s' => \$output ); # --output=somestring or --output somestring

Another reason for preprocessing arguments is to make an empty @@ -329,7 +347,7 @@ Here's an example: ? '< /etc/passwd' : 'ypcat passwd |';

- open(PWD, $pwdinfo) + open(my $pwd, $pwdinfo) or die "can't open $pwdinfo: $!";

This sort of thing also comes into play in filter processing. Because @@ -367,7 +385,7 @@ If you want the convenience of the shell, then Perl's
C<open> is definitely the way to go. On the other hand, if you want finer precision than C's simplistic fopen(3S) provides you should look to Perl's C<sysopen>, which is a direct hook into the open(2) system call. -That does mean it's a bit more involved, but that's the price of +That does mean it's a bit more involved, but that's the price of precision.

C<sysopen> takes 3 (or 4) arguments. @@ -413,24 +431,24 @@ but you'll get the idea.

To open a file for reading:

- open(FH, "< $path"); - sysopen(FH, $path, O_RDONLY); + open(my $fh, "< $path"); + sysopen(my $fh, $path, O_RDONLY);

To open a file for writing, creating a new file if needed or else truncating an old file:

- open(FH, "> $path"); - sysopen(FH, $path, O_WRONLY | O_TRUNC | O_CREAT); + open(my $fh, "> $path"); + sysopen(my $fh, $path, O_WRONLY | O_TRUNC | O_CREAT);

To open a file for appending, creating one if necessary:

- open(FH, ">> $path"); - sysopen(FH, $path, O_WRONLY | O_APPEND | O_CREAT); + open(my $fh, ">> $path"); + sysopen(my $fh, $path, O_WRONLY | O_APPEND | O_CREAT);

To open a file for update, where the file must already exist:

- open(FH, "+< $path"); - sysopen(FH, $path, O_RDWR); + open(my $fh, "+< $path"); + sysopen(my $fh, $path, O_RDWR);

And here are things you can do with C<sysopen> that you cannot do with a regular C<open>. As you'll see, it's just a matter of controlling the @@ -439,23 +457,23 @@ flags in the third argument. To open a file for writing, creating a new file which must not previously exist:

- sysopen(FH, $path, O_WRONLY | O_EXCL | O_CREAT); + sysopen(my $fh, $path, O_WRONLY | O_EXCL | O_CREAT);

To open a file for appending, where that file must already exist:

- sysopen(FH, $path, O_WRONLY | O_APPEND); + sysopen(my $fh, $path, O_WRONLY | O_APPEND);

To open a file for update, creating a new file if necessary:

- sysopen(FH, $path, O_RDWR | O_CREAT); + sysopen(my $fh, $path, O_RDWR | O_CREAT);

To open a file for update, where that file must not already exist:

- sysopen(FH, $path, O_RDWR | O_EXCL | O_CREAT); + sysopen(my $fh, $path, O_RDWR | O_EXCL | O_CREAT);

To open a file without blocking, creating one if necessary:

- sysopen(FH, $path, O_WRONLY | O_NONBLOCK | O_CREAT); + sysopen(my $fh, $path, O_WRONLY | O_NONBLOCK | O_CREAT);

=head2 Permissions E<agrave> la mode

@@ -558,7 +576,7 @@ filename that starts with whitespace. Trailing whitespace
is protected by appending an ASCII NUL byte (C<"\0">) at the end of the string.

$file =~ s#^(\s)#./$1#; - open(FH, "< $file\0") || die "can't open $file: $!"; + open(my $fh, "< $file\0") || die "can't open $file: $!";

This assumes, of course, that your system considers dot the current working directory, slash the directory separator, and disallows ASCII @@ -571,16 +589,16 @@ 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 and non-magical way, you could do this first:

- # "Sam sat on the ground and put his head in his hands. - # 'I wish I had never come here, and I don't want to see + # "Sam sat on the ground and put his head in his hands. + # 'I wish I had never come here, and I don't want to see # no more magic,' he said, and fell silent." - for (@ARGV) { + for (@ARGV) { s#^([^./])#./$1#; $_ .= "\0"; - } - while (<>) { + } + while (<>) { # now process $_ - } + }

But be warned that users will not appreciate being unable to use "-" to mean standard input, per the standard convention. @@ -601,26 +619,32 @@ temporarily, then all you have to do is this: open($path, "< $path") || die "can't open $path: $!"; while (<$path>) { # whatever - } + }

Since you're using the pathname of the file as its handle, you'll get warnings more like

Some warning at scriptname line 29, </etc/motd> line 7.

+A better alternative is to use the L<autodie> pragma, which is included +in the Perl core distribution as of v5.10.1 (and can be installed as far +back as Perl 5.8). Autodie makes C<open> throw an exception object that +provides excellent error messages. + =head2 Single Argument Open

-Remember how we said that Perl's open took two arguments? That was a -passive prevarication. You see, it can also take just one argument. -If and only if the variable is a global variable, not a lexical, you -can pass C<open> just one argument, the filehandle, and it will -get the path from the global scalar variable of the same name. +Remember how we said that Perl's open took three or two arguments? +That was a passive prevarication. You see, it can also take just +one argument. If and only if the variable is a global variable, +not a lexical, you can pass C<open> just one argument, the filehandle, +and it will get the path from the global scalar variable of the same +name:

$FILE = "/etc/motd"; open FILE or die "can't open $FILE: $!"; while (<FILE>) { # whatever - } + }

Why is this here? Someone has to cater to the hysterical porpoises. It's something that's been in Perl since the very beginning, if not @@ -640,11 +664,11 @@ failure status. You don't have to accept the STDIN and STDOUT you were given. You are welcome to reopen them if you'd like.

- open(STDIN, "< datafile") - || die "can't open datafile: $!"; + open(STDIN, '< datafile') + || die "Can't open datafile: $!";

- open(STDOUT, "> output") - || die "can't open output: $!"; + open(STDOUT, '> output') + || die "Can't open output: $!";

And then these can be accessed directly or passed on to subprocesses. This makes it look as though the program were initially invoked @@ -652,9 +676,8 @@ with those redirections from the command line.

It's probably more interesting to connect these to pipes. For example:

- $pager = $ENV{PAGER} || "(less || more)"; - open(STDOUT, "| $pager") - || die "can't fork a pager: $!"; + $pager = $ENV{PAGER} || '(less || more)'; + open(STDOUT, "| $pager") || die "can't fork a pager: $!";

This makes it appear as though your program were called with its stdout already piped into your pager. You can also use this kind of thing @@ -665,18 +688,18 @@ just in a different process: head(100); while (<>) { print; - } + }

sub head { my $lines = shift || 20; - return if $pid = open(STDOUT, "|-"); # return if parent + return if $pid = open(STDOUT, '|-'); # return if parent die "cannot fork: $!" unless defined $pid; while (<STDIN>) { last if --$lines < 0; print; - } + } exit; - } + }

This technique can be applied to repeatedly push as many filters on your output stream as you wish. @@ -694,7 +717,7 @@ just in case.

if (-l $file || ! -f _) { print "$file is not a plain file\n"; - } + }

What other kinds of files are there than, well, files? Directories, symbolic links, named pipes, Unix-domain sockets, and block and character @@ -704,14 +727,14 @@ Not all plain files are text files. That's why there are
separate C<-f> and C<-T> file tests.

To open a directory, you should use the C<opendir> function, then -process it with C<readdir>, carefully restoring the directory +process it with C<readdir>, carefully restoring the directory name if necessary:

- opendir(DIR, $dirname) or die "can't opendir $dirname: $!"; - while (defined($file = readdir(DIR))) { + opendir(my $dir, $dirname) or die "can't opendir $dirname: $!"; + while (defined($file = readdir($dir))) { # do something with "$dirname/$file" } - closedir(DIR); + 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 @@ -734,8 +757,8 @@ C<readlink> is called for: print "$file points to $whither\n"; } else { print "$file points nowhere: $!\n"; - } - } + } + }

=head2 Opening Named Pipes

@@ -767,9 +790,9 @@ With descriptors that you haven't opened using C<sysopen>,
such as sockets, you can set them to be non-blocking using C<fcntl>:

use Fcntl; - my $old_flags = fcntl($handle, F_GETFL, 0) + my $old_flags = fcntl($handle, F_GETFL, 0) or die "can't get flags: $!"; - fcntl($handle, F_SETFL, $old_flags | O_NONBLOCK) + 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, @@ -784,8 +807,8 @@ 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 +one of Perl's two open functions. See +L<perlipc/"Sockets: Client/Server Communication"> for that. Here's an example. Once you have it, you can use FH as a bidirectional filehandle.

use IO::Socket; @@ -814,7 +837,7 @@ handles before doing regular I/O on them:

binmode(STDIN); binmode(STDOUT); - while (<STDIN>) { print } + while (<STDIN>) { print }

Passing C<sysopen> a non-standard flag option will also open the file in binary mode on those systems that support it. This is the equivalent of @@ -834,7 +857,7 @@ sneaky data mutilation behind your back.

while (sysread(WHENCE, $buf, 1024)) { syswrite(WHITHER, $buf, length($buf)); - } + }

Depending on the vicissitudes of your runtime system, even these calls may need C<binmode> or C<O_BINARY> first. Systems known to be free of @@ -897,7 +920,7 @@ if you're going to be blocking: print "Waiting for lock..."; flock(FH, LOCK_SH) or die "can't lock filename: $!"; print "got it.\n" - } + } # now read from FH

To get an exclusive lock, typically used for writing, you have to be @@ -974,7 +997,7 @@ The two-argument form of C<binmode> is being used, for
example For more detailed discussion about PerlIO see L<PerlIO>; for more detailed discussion about Unicode and I/O see L<perluniintro>.

-=head1 SEE ALSO +=head1 SEE ALSO

The C<open> and C<sysopen> functions in perlfunc(1); the system open(2), dup(2), fopen(3), and fdopen(3) manpages; @@ -982,7 +1005,7 @@ the POSIX documentation.

=head1 AUTHOR and COPYRIGHT

-Copyright 1998 Tom Christiansen. +Copyright 1998 Tom Christiansen.

This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself.