在perl中有<FH>,<>或<*>时会发生什么?

Squ*_*awk 5 io perl glob filehandle

如果这个问题听起来很简单,我很抱歉,我的目的是深入了解这些(这些?)特定的操作符是如何工作的,我无法在perldocs中找到令人满意的描述(它可能存在于某个地方,我只是不能找到我的生活)

特别是,我有兴趣知道是否

一个) <>

b)<*>或者不管怎么说

C) <FH>

基本相似或不同,以及如何在内部使用它们.

我建立了自己的测试功能,以获得对此的一些见解(如下所示).我仍然没有完全理解(我的理解可能甚至是错误的)但这是我得出的结论:

  • <>
    • 在标量上下文中:读取正在读取的"当前文件"的下一行(在@ARGV中提供).问题:这似乎是一个非常特殊的场景,我想知道为什么它是这样的,是否可以推广.还有什么是正在阅读的"当前文件"?它在文件句柄中吗?什么是柜台?
    • 在列表上下文中:将@ARGV中的所有文件读入数组
  • <list of globs>
    • 在标量上下文中:在当前文件夹中找到的与glob匹配的第一个文件的名称.问题:为什么当前文件夹?我该如何改变?这是改变这种做什么的唯一方法,比如</ home/*>?
    • 在列表上下文中:与当前文件夹中的glob匹配的所有文件.
  • <FH>只是在分配给变量时似乎返回undef. 问题:为什么它不合适?它没有类型吗?当FH不是裸字文件句柄时,这种行为是否相似?

一般问题:在执行期间处理<>和其他值的是什么?在标量上下文中,返回的是任何类型的引用,还是我们分配给它们的变量,在那一点上与任何其他非ref标量相同?

我也注意到即使我按顺序分配它们,每次都会重置输出.也就是说,当我这样做时,我会假设

$thing_s = <>;
@thing_l = <>;
Run Code Online (Sandbox Code Playgroud)

@thing_l会丢失第一个项目,因为它已被收到$thing_s.为什么不是这样?

用于测试的代码:

use strict;
use warnings;
use Switch;
use Data::Dumper;

die "Call with a list of files\n" if (@ARGV<1);
my @whats = ('<>','<* .*>','<FH>');
my $thing_s;
my @thing_l;
for my $what(@whats){
    switch($what){
                    case('<>'){
                        $thing_s = <>;
                        @thing_l = <>;
                    }
                    case('<* .*>'){
                            $thing_s = <* .*>;
                            @thing_l = <* .*>;
                    }
                    case('<FH>'){
                            open FH, '<', $ARGV[0];
                            $thing_s = <FH>;
                            @thing_l = <FH>;
                    }

    }
    print "$what in scalar context is: \n".Dumper($thing_s)."\n";
    print "$what in list context is: \n".Dumper(@thing_l)."\n";
}
Run Code Online (Sandbox Code Playgroud)

amo*_*mon 12

这些<>东西都是迭代器.所有这些变体都有共同的行为:

  • 在列表上下文中使用,返回所有剩余元素.
  • 在标量上下文中使用,仅返回下一个元素.
  • 在标量上下文中使用,undef一旦迭代器耗尽就会返回.

最后两个属性使其适合用作while循环中的条件.

有两种迭代器可用于<>:

  • 文件句柄.在这种情况下<$fh>相当于readline $fh.
  • 全球,所以<* .*>相当于glob '* .*'.

<>当它包含无,赤字或简单标量时,将被解析为readline.可以嵌入更复杂的表达式<{ ... }>.

在所有其他情况下,它被解析为glob.这可以通过使用引号显式化:<"* .*">但您应该明确地使用glob函数来代替.

一些细节不同,例如保留迭代器状态的位置:

  • 从文件句柄读取时,文件句柄保持迭代器状态.
  • 使用glob表单时,每个glob表达式都有自己的状态.

另一部分是迭代器可以重启:

  • glob返回后重启undef.
  • 文件句柄只能通过搜索重新启动 - 并非所有FH都支持此操作.

如果未使用文件句柄<>,则默认为特殊ARGV文件句柄.行为<ARGV>如下:

  • 如果@ARGV是空的,那ARGV就是STDIN.
  • 否则,将元素@ARGV视为文件名.执行以下伪代码:

    $ARGV = shift @ARGV;
    open ARGV, $ARGV or die ...; # careful! no open mode is used
    
    Run Code Online (Sandbox Code Playgroud)

    $ARGV标持有的文件名和ARGV文件句柄认为文件句柄.

  • 什么时候ARGV会打开eof下一个文件@ARGV.
  • 只有当@ARGV完全为空时才能<>返回undef.

这实际上可以用作从许多文件中读取的技巧:

local @ARGV = qw(foo.txt bar.txt baz.txt);
while (<>) {
  ...;
}
Run Code Online (Sandbox Code Playgroud)