2016-12-07 96 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"; 
}