2010-02-22 38 views
5

如果我有一個函數可能會傳遞一個文件名或各種文件句柄或typeglobs,函數如何區分這些參數 - 包括告訴區別,例如,在*DATA*STDIN之間?Perl子程序如何區分文件名,文件handes,* DATA和* STDIN?

更新的代碼,根據迄今收到的答案謝謝大家。

use strict; 
use warnings; 
use FileHandle; 

sub file_thing_type { 
    my ($f) = shift; 
    my $type; 
    my $r = ref $f; 
    if ($r eq 'GLOB' or ref(\$f) eq 'GLOB'){ 
     # Regular and built-in file handles. 
     my $fn = fileno $f; 
     if (defined $fn){ 
      my %built_in = (
       'STDIN' => fileno(*STDIN), 
       'STDOUT' => fileno(*STDOUT), 
       'STDERR' => fileno(*STDERR), 
       'DATA' => fileno(*DATA), 
      ); 
      for my $k (keys %built_in){ 
       if (defined $built_in{$k} and $built_in{$k} == $fn){ 
        $type = $k; 
        last; 
       } 
      } 
      $type = 'regular file handle' unless defined $type; 
     } 
     else { 
      $type = 'non-IO glob'; 
     } 
    } 
    elsif ($r){ 
     # A reference of some kind. 
     $type = $r; 
     # Might be an IO object. Has it been opened? 
     { 
      no warnings 'unopened'; 
      $type .= ' opened' if -f $f; 
     } 
    } 
    else { 
     # File name or just some other value? 
     $type = -f $f ? 'file name' : 'other'; 
    } 
    return $type; 
} 

open(my $h, '<', $0) or die $!; 

printf "%12s => %s\n", 
     $_->[0], 
     file_thing_type($_->[1]) 
for (
    [ 'handle',  $h     ], # regular file handle 
    [ 'DATA',  *DATA    ], # DATA if source has DATA section; else non-IO glob 
    [ 'STDIN',  *STDIN    ], # STDIN 
    [ 'STDOUT',  *STDOUT    ], # STDOUT 
    [ 'STDERR',  *STDERR    ], # STDERR 
    [ 'FOO',  *FOO, *FOO   ], # non-IO glob 
    [ 'FileHandle', FileHandle->new  ], # FileHandle 
    [ 'FileHandle', FileHandle->new($0) ], # FileHandle opened 
    [ 'file name', $0     ], # file name 
    [ 'not file', ''     ], # other 
    [ 'misc',  {bar=>1}   ], # HASH 
); 

__END__ 
+1

它們都是文件句柄。你究竟想要測試什麼? 您可以使用手柄上的「-t」測試來檢查它是否來自/去往終端(TTY),這通常對於STDIN和STDOUT是正確的,除非管道連接。 – amphetamachine 2010-02-22 03:36:42

+0

請讓我們知道你想做什麼的更廣泛的背景。爲什麼你需要能夠DATA'和'STDIN'之間'區別? – 2010-02-22 14:37:55

+1

@gbacon說實話,我不能肯定。我工作的事昨天深夜,並認爲這可能有助於能夠區分。然後,我注意到,數據::自卸車能夠分開(排序)告訴他們,所以我想這個問題可能有一個簡單的答案,我提出它左右。從那時起,我對我的項目思維的發展,所以現在我們只是到好奇。 :) – FMc 2010-02-22 14:43:03

回答

2

更新:可能被分配到*DATA*STDIN水珠變量之間的區分問題是fileno工作:

 
sub data_or_stdin { 
    my $x = shift; 
    if (fileno($x) == fileno(DATA)) { 
    return "DATA"; 
    } elsif (fileno($x) == fileno(STDIN)) { 
    return "STDIN"; 
    } else { 
    return "NEITHER"; 
    } 
} 

print "DATA: ", data_or_stdin(*DATA), "\n"; 
print "STDIN: ", data_or_stdin(*STDIN), "\n"; 
open(ZZZ, ">>", "zzz"); close ZZZ; 
open(ZZZ, "<", "zzz"); print "ZZZ: ", data_or_stdin(*ZZZ), "\n"; close ZZZ; 
open($fh, "<", "zzz"); print "\$fh=ZZZ: ", data_or_stdin($fh), "\n"; close $fh; 
$fh = *DATA; print "\$fh=DATA: ", data_or_stdin($fh), "\n"; 
$fh = *STDIN; print "\$fh=STDIN: ", data_or_stdin($fh), "\n"; 

__END__ 
stuff; 
 
$ perl data_or_stdin.pl 
DATA: DATA 
STDIN: DATA 
ZZZ: NEITHER 
$fh=ZZZ: NEITHER 
$fh=DATA: DATA 
$fh=STDIN: DATA 

如果$f是一個文件句柄,那麼ref $fref \$f將是"GLOB" 如果$f是標量,則ref \$f將是"SCALAR"

sub filehandle_or_scalar { 
    my $x = shift; 
    if (ref $x eq "GLOB" || ref \$x eq "GLOB") { 
     return "filehandle"; 
    } elsif (ref \$x eq "SCALAR") { 
     return "scalar"; 
    } else { 
     return "not filehandle or scalar"; 
    } 
} 

print "STDIN: ", filehandle_or_scalar(*STDIN), "\n"; 
print "\$_: ", filehandle_or_scalar($_), "\n"; 
open($fh, ">", "zzz"); 
print "\$fh: ", filehandle_or_scalar($fh), "\n"; 
print "string: ", filehandle_or_scalar('file.txt'), "\n"; 
print "ref: ", filehandle_or_scalar(\$x), "\n" 

########################################### 

$ perl filehandle_or_scalar.pl 
STDIN: filehandle 
$_: scalar 
$fh: filehandle 
string: scalar 
ref: not filehandle or scalar 
+0

子is_filehandle { 應該 子filehandle_or_scalar { – 2010-02-22 04:25:54

1

你可以使用模式上* STDIN,*數據等的stringafied文件句柄匹配...

if ($f =~ /\bSTDIN$/) { 
    return "STDIN"; 
} elsif ($f =~ /\bDATA$/) { 
    return "DATA"; 
} 

哈克,但可能足以...

1

mobrule的方法看起來承諾:

perl -E 'open $fh, "<", "/dev/null"; say ref $fh;' 

將輸出GLOB。然而,這樣會

perl -E 'say ref \*FOO;' 

一個「真實」的文件句柄也會有 相關的文件描述符它,你可以決定使用fileno

perl -MData::Dumper -E 'open $fh, "<", "/dev/null"; say Data::Dumper::Dumper([fileno $fh, fileno \*STDIN, fileno \*FOO])' 

將輸出類似:

$VAR1 = [ 
      3, 
      0, 
      undef 
     ]; 

您可以使用它來告訴GLOB正在用於文件I/O從 不是。在UNIX系統上,標準輸入流按照慣例與文件描述符關聯。

想到的另一件事是一個綁定到 文件句柄的類。這些需要實現一個特定的接口,您可以使用can進行測試。有關此接口的詳細信息,請參閱關聯VARIABLE,CLASSNAME,列表 條目perlfunc