46

I've got two questions about the Perl open function:

1) I seem to remember from Perl Best Practices that the 3-argument version of open is better than the two argument version, e.g.

open(OUT, '>>', $file);

vs.

open(OUT, ">>$file");

Why is that? I was trying to tell somebody to use the 3-argument version the other day but couldn't seem to back it up with anything.

2) I also seem to remember autovivified filehandles being favored over bareword filehandles (they called something different)? And also couldn't remember why, e.g.

open(my $out, '>>', $file);

vs.

open(OUT, '>>', $file);

Is it a strict thing? I seem to remember being able to use OUT with strict but I can't remember.

ThisSuitIsBlackNot
  • 23,492
  • 9
  • 63
  • 110
Morinar
  • 3,460
  • 8
  • 40
  • 58
  • dupe: http://stackoverflow.com/questions/318789/whats-the-best-way-to-open-and-read-a-file-in-perl – Ether Sep 25 '09 at 23:06
  • 1
    It's because Perl::Critic advices this :) – Alexandr Ciornii Sep 26 '09 at 09:23
  • 3
    Not a dupe, this is asking why it is the best way to do that. – Brad Gilbert Sep 28 '09 at 02:06
  • Sorry for the edits...I'd never heard these called "autovivified filehandles" (I've always heard "lexical filehandle") and was trying to improve searchability, but now I see autovivification really is involved and the docs do refer to them that way. Rolled back to the previous version. – ThisSuitIsBlackNot Jan 07 '16 at 15:52

3 Answers3

64
  • Using typeglobs for filehandles (like OUT) is not a good idea, as they are global across your entire program - you need to be sure that no other routine including those in modules are using the same name (including in the future).
  • Using the two-argument form of open exposes your application to mis-behaviour caused by variables containing special characters, for example my $f; open $f, ">$some_filename"; is exposed to the bug where $some_filename containing a leading > will change the program's behaviour.

Using the three-argument form avoids this by separating the mode and filename into separate arguments where they can't interfere.

Moreover, using the lots-of-arguments form with pipes is a very good idea:

open $pipe, '|-', 'sendmail', 'fred@somewhere.fake';

Is better than doing it all as a single string – it avoids possible shell injection etc.

daxim
  • 39,270
  • 4
  • 65
  • 132
MarkR
  • 62,604
  • 14
  • 116
  • 151
  • 1
    Thanks MarkR. That was pretty much EXACTLY the set of answers I was looking for. Glad to know there is actually a legitimate reason for me having it done it that way for the last few years. – Morinar Sep 25 '09 at 22:05
  • 3
    Notes on compatibility: 3-arg open and `open my $fh, ...` work beginning in 5.6.0. `open my $fh, '|-', LIST` (list pipe open) works beginning in 5.8.0. – hobbs Sep 29 '09 at 01:40
  • 1
    There is no reason to use the ugly form of pipe-open on literals of known content, such as the one suggested. Furthermore, you break shell handling of complex pipelines. Bad bad bad. – tchrist Mar 18 '12 at 04:19
  • I'd also like to point out that _autovivified filehandles_ are way easier to pass as arguments to methods and subroutines. You can even open a file in a subroutine, and pass the file handle back to the caller. – David W. Feb 27 '14 at 16:10
16

Tackling #2:

OUT is a global filehandle and using it exposes you to insidious bugs like this:

sub doSomething {
  my ($input) = @_;
  # let's compare $input to something we read from another file
  open(F, "<", $anotherFile);
  @F = <F>; 
  close F;
  &do_some_comparison($input, @F);
}

open(F, "<", $myfile);
while (<F>) {
    &doSomething($_);   # do'h -- just closed the F filehandle
}
close F;
Paul Nathan
  • 39,638
  • 28
  • 112
  • 212
mob
  • 117,087
  • 18
  • 149
  • 283
13

One aspect to keep in mind is that the two-arg form is broken. Consider a file named ' abc' (that is, a file name with a leading blank). You cannot open the file:

open my $foo, ' abc' or die $!;
open my $foo, '< abc' or die $!;
open my $foo, '<  abc' or die $!;
# nothing works

The space gets dropped and so the file can no longer be found. Such a scenario is highly improbable, but definitely a problem. The three-arg form is immune to this:

open my $foo, '<', ' abc' or die $!;
# works

This thread from perlmonks is as good a discussion as any of the issue. Just bear in mind that in 2001, the three-arg form was still considered new, and thus not suitable for portable code, since Perl programs would die with a syntax error if run on a 5.005 interpreter. This is no longer the case: perl 5.005 is beyond deprecated, it is obsolete.

dland
  • 4,319
  • 6
  • 36
  • 60
  • 16
    No, the two-argument form of open, or the one-argument form for that matter, is *not* broken. It is working as designed, documented, and advertised. It simply may be that *magic open* isn't what you need. Another plug for three-argument open is that the middle argument can — and often should — include the stream's encoding. – tchrist Oct 30 '10 at 16:23