2016-12-07 77 views
7

我试图编写一个程序,其中perl打开一个文件,但如果该文件不存在或因某种原因无法打开,则会回退到另一个文件。相关线路是:回退打开文件Perl

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

最后,我想通了,:

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

工作。这两个陈述之间有什么区别,为什么不是第一个工作,是第二个正确的方法来做到这一点,还是还存在一些问题呢?

编辑:如果有问题,我正在使用perl 5.12,并且第一个在"/path/to/file"存在的情况下失败。我的倾向是,如果第一次打开成功,第二次open不应该运行,那么为什么第二次覆盖$fh

+0

首先没有问题,尽管变量再次被重新声明。 –

+0

@JayKumarR好吧,它没有工作。在下一行'$ fh'不是两个文件的打开文件句柄。 – Chris

+1

务必使用'use strict;使用警告qw(all);'!!!! – ikegami

回答

8

我声明了一个变量。如果您在同一范围内使用两次相同的名称,稍后提及它将是第二个,而不是第一个。您的代码将触发"my" variable ... masks earlier declaration in the same statement警告(如果您应该按照要求启用警告)。因此,如果第一次打开成功,它会设置一个$fh变量,该变量以后不可访问,第二个变量留在未记录的未定义状态,因为其声明并未实际执行。 (请参阅perldoc perlsyn中的“这里是龙”警告,并意识到A or B相当于B unless A。)

您的“工作”代码也被破坏;而my返回新声明的变量,然后可以进行设置,词法的范围(后面提到它找到变量)实际上并没有开始,直到下面的语句。所以你的第一个$fh是在后面的行会被访问的词汇,但第二个实际上是一个全局变量(或者如果你使用的是严格的,那么是一个错误)。

正确的代码是:

my $fh; 
open $fh, ... or open $fh, ...; 
4

还有人说为什么现有的代码不能正常工作,而且还提供有竞争条件的版本:文件的状态可能会当你检查它之间改变当你打开它。你的情况相当温和,但它会产生微妙的错误和安全漏洞。通常,您可以通过尝试打开文件来检查是否可以打开文件。

下面是扩展到多个文件的更一般的方式,可以让您知道打开了哪个文件,并且不包含竞争条件。

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"; 
}