Perl子例程如何区分文件名、文件句柄、*数据和*STDIN?

Perl子例程如何区分文件名、文件句柄、*数据和*STDIN?,perl,filehandle,typeglob,Perl,Filehandle,Typeglob,如果我有一个可以传递文件名或各种文件句柄或typeglobs的函数,那么该函数如何区分这些参数——包括告诉它们之间的区别,例如,*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

如果我有一个可以传递文件名或各种文件句柄或typeglobs的函数,那么该函数如何区分这些参数——包括告诉它们之间的区别,例如,
*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__
使用严格;
使用警告;
使用文件句柄;
子文件类型{
我的($f)=班次;
我的$type;
my$r=ref$f;
如果($r均衡器‘GLOB’或参考(\$f)均衡器‘GLOB’){
#常规和内置文件句柄。
my$fn=fileno$f;
如果(定义为$fn){
我的内置%u=(
'STDIN'=>fileno(*STDIN),
'STDOUT'=>fileno(*STDOUT),
'STDERR'=>fileno(*STDERR),
“数据”=>fileno(*DATA),
);
对于我的$k(钥匙%内置){
if(定义为{$k}中的$build_和{$k}中的$build_==$fn){
$type=$k;
最后;
}
}
$type=‘常规文件句柄’,除非定义了$type;
}
否则{
$type='非IO全局';
}
}
elsif($r){
#某种参考资料。
$type=$r;
#可能是IO对象。它已打开吗?
{
没有“未打开”的警告;
$type.='opened'如果-f$f;
}
}
否则{
#文件名还是其他值?
$type=-f$f?“文件名”:“其他”;
}
返回$type;
}

open(my$h,更新:区分可能分配给
*数据
*STDIN
全局的变量的问题是:


您可以对*STDIN、*DATA等的stringafied文件句柄使用模式匹配

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

有点老套,但可能已经足够了……

mobrule的方法看起来很有希望:

perl -E 'open $fh, "<", "/dev/null"; say ref $fh;'
“真实”文件句柄还将有一个与 您可以使用
fileno
确定它:

perl -MData::Dumper -E 'open $fh, "<", "/dev/null"; say Data::Dumper::Dumper([fileno $fh, fileno \*STDIN, fileno \*FOO])'
您可以使用它来告诉正在用于文件I/O的GLOB 在UNIX系统上,标准输入流按照惯例与文件描述符0关联

我想到的另一件事是一个与 这些需要实现一个特定的接口 可以测试是否使用
can
。请参阅tie变量、CLASSNAME、LIST
perlfunc中的条目,了解有关此接口的详细信息。

它们都是文件句柄。您到底想测试什么?您可以使用句柄上的“-t”测试来检查它是否来自/前往终端(TTY),这对于STDIN和STDOUT通常是正确的,除非是管道。请让我们知道您想要做什么的更广泛的背景。为什么您需要能够区分
数据
STDIN
?@gbacon老实说,我不确定。我昨晚很晚才在做一些事情,并认为它可能有助于区分guish。然后我注意到Data::Dumper能够将它们区分开来(某种程度上),所以我认为这个问题可能有一个简单的答案,于是我提出了这个问题。从那时起,我对我的项目的思考不断发展,所以现在我们只剩下好奇了。:)sub is_filehandle{应该是sub filehandle_或_scalar{
if ($f =~ /\bSTDIN$/) {
    return "STDIN";
} elsif ($f =~ /\bDATA$/) {
    return "DATA";
}
perl -E 'open $fh, "<", "/dev/null"; say ref $fh;'
perl -E 'say ref \*FOO;'
perl -MData::Dumper -E 'open $fh, "<", "/dev/null"; say Data::Dumper::Dumper([fileno $fh, fileno \*STDIN, fileno \*FOO])'
$VAR1 = [
          3,
          0,
          undef
        ];