Why is three-argument open calls with autovivified

2018-12-31 15:12发布

问题:

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.

回答1:

  • 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.



回答2:

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;


回答3:

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.