2010-02-22 12 views
5

Bir dosya adı veya çeşitli dosya kolları veya typeglobs aktarabileceğiniz bir işlevi varsa, işlev bu argümanları arasında ayrım nasıl - *DATA ve *STDIN arasında, örneğin, farkı anlatan dahil? yanıtlara dayalıPerl alt yordamı dosya adları, dosya tanıtıcıları, * DATA ve * STDIN arasında nasıl ayırt edebilir?

Güncelleme kod, herkesi şimdiye kadar Teşekkür aldı.

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

Hepsi dosya tanıtıcısı konum. Tam olarak neyi test etmeye çalışıyorsun? Boru hattında olmadıkça STDIN ve STDOUT için normalde geçerli olacak bir terminalden (TTY) olup olmadığını kontrol etmek için tutamağın üzerindeki "-t" testini kullanabilirsiniz. – amphetamachine

+0

Lütfen ne yapmak istediğinizin daha geniş bağlamını bize bildirin.Neden "VERİ" ve "STDİN" arasında ayrım yapabilmeniz gerekiyor? –

+1

@gbacon Bütün dürüstlükte, emin değilim. Dün gece bir şey üzerinde çalışıyordum ve ayırt edebilmek için yardımcı olabileceğini düşündüm. Sonra, Data :: Dumper'ın onları bir şekilde ayırt edebildiğini fark ettim, bu yüzden sorunun basit bir cevabı olabileceğini düşündüm. O zamandan beri, projem hakkındaki düşüncelerim gelişti, şimdi de sadece merakımız var. :) – FMc

cevap

2

Güncelleme: $f ise

 
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 

: *DATA veya *STDIN Neználkovo atanabilir bir değişken arasında ayrım problemi fileno işidir bir filehandle, daha sonra ref $f veya ref \$folacaktır $f Eğer bir sayıl, sonra ref \$f"SCALAR" olacaktır.

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

alt is_filehandle { alt dosya_sayısı_or_scaları { olmalıdır. –

1

Sen * STDIN, * VERİ vb stringafied filehandles eşleşen deseni kullanabilirsiniz ...

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

Hacky ancak yeterli olabilir ...

1

mobrule yaklaşımı görünüyor umut verici:

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

irade çıkışı GLOB.

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

irade çıktı gibi bir şey:

$VAR1 = [ 
      3, 
      0, 
      undef 
     ]; 
Ancak böylece

perl -E 'say ref \*FOO;' 

Bir "gerçek" dt ayrıca fileno kullanarak belirleyebilir hangi ile ilişkili bir dosya tanıtıcı olacak olacak

Bunu, G/Ç için olmayan bir dosyada kullanılmakta olan bir GLOB'a bildirmek için kullanabilirsiniz. UNIX sistemlerinde standart giriş akışı, kural gereği dosya tanımlayıcısı 0 ile ilişkilendirilmiştir. akla gelen

Başka bir şey bir dosya tanıtıcısına bağlı bir sınıftır. Bunlar, 'un can'u kullanarak test edebileceğiniz belirli bir arabirimi uygulama ihtiyacı duyar. kravat VARIABLE, SinifAdi, LİSTESİ bu arayüz hakkında ayrıntılı bilgi için perlfunc yılında girişine bakın.

İlgili konular