Papal Open File Perl

I tried to write a program in which perl opens one file, but returns to another if this file does not exist or does not open for any reason. Corresponding line:

open(my $fh,"<","/path/to/file") or open (my $fh,"<","/path/to/alternate/file") or die

In the end, I realized that:

open(my $fh,"<","/path/to/file") or open ($fh,"<","/path/to/alternate/file") or die

worked. What is the difference between these two statements, why does the first work not work, and the second is the right way to do this, or is there still a problem with it?

Edit: if that matters, I use perl 5.12 , and the first fails when "/path/to/file" exists. My tendency is that the second open should not start if the first open is successful, so why will $fh be overwritten by the second?

+7
scope perl
source share
2 answers

my declares a variable. If you use it twice with the same name in the same scope, later references to it will be second, not first. Your code will raise the warning "my" variable ... masks earlier declaration in the same statement (if you enable the warnings as you should.) Therefore, if the first open is completed successfully, it sets the $fh variable, which is not available later, and the second the variable remains in an undocumented, undefined because its declaration was not actually executed. (See the warning “There will be dragons” in perldoc perlsyn and understand that A or B equivalent to B unless A )

Your working code also does not work; while my returns a newly declared variable that can be set, the lexical scope (where later mentions of this find the variable) does not actually begin until the next statement. Thus, your first $fh is lexical, which will be accessed on later lines, and the second is actually a global variable (or an error if you use a strict one, as it should).

The correct code is:

 my $fh; open $fh, ... or open $fh, ...; 
+8
source share

Others said why the existing code did not work, but also suggested versions that have race conditions: the state of the file can change when you check it and when you open it. This is pretty mild in your case, but it can create subtle bugs and security holes. In general, you are checking to see if you can open the file by trying to open the file.

Here's a more general way that scales to multiple files, lets you know which file is open, and does not contain race conditions.

 use Carp; sub try_open { my @files = @_; for my $file (@files) { if( open my $fh, "<", $file ) { return { fh => $fh, file => $file }; } } croak "Can't open any of @files"; } 
+4
source share

All Articles