【问题标题】:How can a Perl subroutine distinguish between file names, file handes, *DATA, and *STDIN?Perl 子例程如何区分文件名、文件名称、*DATA 和 *STDIN?
【发布时间】:2010-02-22 03:16:44
【问题描述】:

如果我有一个函数可能会传递一个文件名或各种文件句柄或 typeglob,该函数如何区分这些参数 - 包括区分*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__

【问题讨论】:

  • 它们都是文件句柄。你到底想测试什么?您可以在句柄上使用“-t”测试来检查它是否来自/去往终端 (TTY),这对于 STDIN 和 STDOUT 通常是正确的,除非通过管道传输。
  • 请让我们知道您想要做的更广泛的背景。为什么需要能够区分DATASTDIN
  • @gbacon 老实说,我不确定。我昨晚深夜在做一些事情,并认为这可能有助于区分。然后我注意到 Data::Dumper 能够将它们区分开来(有点),所以我认为这个问题可能有一个简单的答案,所以我提出了它。从那时起,我对我的项目的想法发生了变化,所以现在我们只是出于好奇。 :)

标签: perl filehandle typeglob


【解决方案1】:

更新:区分可能分配给*DATA*STDIN glob 的变量的问题是fileno 的工作:

子数据或标准输入{ 我的 $x = 班次; if (fileno($x) == fileno(DATA)) { 返回“数据”; } elsif (fileno($x) == fileno(STDIN)) { 返回“标准输入”; } 别的 { 返回“都没有”; } } 打印 "DATA: ", data_or_stdin(*DATA), "\n"; 打印 "STDIN:", data_or_stdin(*STDIN), "\n"; 打开(ZZZ,“>>”,“zzz”);关闭 ZZZ; 打开(ZZZ,“ $ perl data_or_stdin.pl 数据:数据 标准输入:数据 ZZZ:都没有 $fh=ZZZ:都不是 $fh=数据:数据 $fh=标准输入:数据

如果$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

【讨论】:

  • sub is_filehandle { 应该是 sub filehandle_or_scalar {
【解决方案2】:

您可以在 *STDIN、*DATA 等的字符串文件句柄上使用模式匹配...

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

Hacky,但可能就足够了......

【讨论】:

    【解决方案3】:

    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
            ];
    

    您可以使用它来告诉正在用于文件 I/O 的 GLOB 一个不是。在 UNIX 系统上,按照约定,标准输入流与 文件描述符 0 相关联。

    想到的另一件事是与 文件句柄。这些需要实现一个特定的接口,你 可以测试使用can。查看tie VARIABLE,CLASSNAME,LIST perlfunc 中的条目以了解有关此接口的详细信息。

    【讨论】:

      猜你喜欢
      • 2015-09-27
      • 1970-01-01
      • 1970-01-01
      • 2012-11-04
      • 1970-01-01
      • 2010-09-17
      • 2022-01-14
      • 1970-01-01
      • 2019-06-16
      相关资源
      最近更新 更多