【问题标题】:Can I get a handle to - source?我可以得到一个句柄 - 来源吗?
【发布时间】:2012-08-01 21:53:55
【问题描述】:

看起来 main 中有一个名为 '_<-'(不带引号)的符号,其方式与 看起来像它们可能是句柄的其他事物相同:例如,'_</usr/perl/lib/Carp.pm' .

有什么方法可以使用吗?

如果我希望读取输入源,我是否必须使用源过滤器?


回复 mob:我不知道 Debug 会在哪里打开。在我转储基表后,%INC 转储显示:

$VAR1 = {
      'warnings/register.pm' => 'C:/strawberry/perl/lib/warnings/register.pm',
      'XSLoader.pm' => 'C:/strawberry/perl/lib/XSLoader.pm',
      'English.pm' => 'C:/strawberry/perl/lib/English.pm',
      'Tie/Hash/NamedCapture.pm' => 'C:/strawberry/perl/lib/Tie/Hash/NamedCapture.pm',
      'unicore/lib/Perl/_PerlIDS.pl' => 'C:/strawberry/perl/lib/unicore/lib/Perl/_PerlIDS.pl',
      'unicore/Heavy.pl' => 'C:/strawberry/perl/lib/unicore/Heavy.pl',
      'warnings.pm' => 'C:/strawberry/perl/lib/warnings.pm',
      'utf8.pm' => 'C:/strawberry/perl/lib/utf8.pm',
      'Config.pm' => 'C:/strawberry/perl/lib/Config.pm',
      'overloading.pm' => 'C:/strawberry/perl/lib/overloading.pm',
      'Symbol.pm' => 'C:/strawberry/perl/lib/Symbol.pm',
      'Carp.pm' => 'C:/strawberry/perl/lib/Carp.pm',
      'bytes.pm' => 'C:/strawberry/perl/lib/bytes.pm',
      'Exporter/Heavy.pm' => 'C:/strawberry/perl/lib/Exporter/Heavy.pm',
      'utf8_heavy.pl' => 'C:/strawberry/perl/lib/utf8_heavy.pl',
      'strict.pm' => 'C:/strawberry/perl/lib/strict.pm',
      'Exporter.pm' => 'C:/strawberry/perl/lib/Exporter.pm',
      'vars.pm' => 'C:/strawberry/perl/lib/vars.pm',
      'constant.pm' => 'C:/strawberry/perl/lib/constant.pm',
      'Errno.pm' => 'C:/strawberry/perl/lib/Errno.pm',
      'overload.pm' => 'C:/strawberry/perl/lib/overload.pm',
      'Data/Dumper.pm' => 'C:/strawberry/perl/lib/Data/Dumper.pm'
    };

【问题讨论】:

  • 我已经更新了我的答案,以展示如何在没有源过滤器的情况下读取源文件,无论源文件是否具有 __DATA__ 段。
  • 谢谢,@DavidO。我将在编译时测试它是如何工作的。
  • 几天后跟进,看看我提供的解决方案是否适合您。
  • @DavidO,我还没有机会尝试一下。我想知道的一件事是它在编译期间是否有效?我以为我会自己提供这个答案,但我还是没有回过头来。
  • 我已将解决方案封装在 BEGIN{ ... } 块中。只要它的BEGIN 块出现在任何其他调用read_source()BEGIN 块之前,是的,它可以在编译期间工作(如果您所说的“在编译期间工作”是“在 BEGIN 块中可用”)。

标签: perl perl-io


【解决方案1】:

您在 perl 调试器中看到了这个?这可能是这些符号表条目的来源:参见DATA STRUCTURES MAINTAINED BY CORE section of the perldoc in your perl5db.pl file

我能看到在符号表中获取 _<- 条目的唯一方法是仅使用 -d 开关启动 perl,然后将 Perl 程序输入到标准输入中,例如:

$ perl -d

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

print "Hello world\n";
<Ctrl-D>
main::(-:1):    print "Hello world\n";
  DB<1>

从这里开始,@{"_&lt;-"}(或@{$main::{"_&lt;-"}})包含您的输入,${"_&lt;-"}${$main::{"_&lt;-"}} 包含您的文件的“名称”(只是-),并且%{"_&lt;-"}/%{$main::{"_&lt;-"}} 保留有关从标准输入单步执行代码的断点和操作的信息。

没有strict refs,您还可以使用类似的方式查看此数据

  DB<6> $name="_<-"

  DB<7> p ${$name}
-
  DB<8> p @{$name}
BEGIN { require 'perl5db.pl' };
print "Hello world\n";

  DB<9> p %{$name}

没有与_&lt;-(或任何其他_&lt;... 符号)的符号表条目关联的文件句柄。

【讨论】:

  • 啊,文件顶部的搜索很有趣。这完全可以在编译阶段完成吗?
【解决方案2】:

如果我希望读取输入源,我是否必须使用源过滤器?

如果源文件有__END____DATA__ 标签,则DATA 文件句柄可用。 ...这本身就很无聊。有趣的是,您可以seek 定位到位置 0,这将带您到源文件的顶部:

use Carp;

print "Just another Perl hacker,\n";

eval { 
    no warnings qw/unopened/;
    seek DATA, 0, 0 
      or croak "Script lacking __END__ or __DATA__ tag has no DATA filehandle.";
};
if( !$@ ) {
    while(<DATA>){
        print;
    }
}
else {
    carp $@;
}

__END__

此脚本将执行(打印“只是另一个 Perl 黑客”),然后通过打印自己的源代码来完成。

在上面的代码中,如果eval 块确实捕获了异常,则回退可能是使用 FindBin 和$0,打开源文件,然后读取它。综上所述,它的外观如下:

BEGIN {
    use Carp;

    sub read_source {
        my $source;
        local $/ = undef;
        eval {
            no warnings qw( unopened );
            my $DATA_position = tell DATA;
            croak "'tell DATA' failed: Probably no __END__ or __DATA__ segment."
              if $DATA_position < 0;
            seek DATA, 0, 0
              or croak
              "'seek DATA' failed: Probably no __END__ or __DATA__ segment.";
            $source = <DATA>;
            seek DATA, $DATA_position, 0 or croak    # Must leave *DATA usable.
              "seek to reset DATA filehandle failed after read.";
        };
        if ($@) {
            croak $@ if $@ =~ /reset/;    # Unstable state: Shouldn't be possible.
            eval {
                require FindBin;
                no warnings 'once';
                open my $source_fh, $FindBin::Bin . '/' . $0 or croak $!;
                $source = <$source_fh>;
            };
            croak "Couldn't read source file from *DATA or \$0: $@" if $@;
        }
        return $source;
    }
};

print read_source(), "\n";

这个 sn-p 首先尝试从DATA 读取,这消除了加载 FindBin 和打开新文件句柄的需要。如果失败,那么它会尝试 FindBin 方法。如果两者都失败,则会引发异常。最终成功状态将整个源文件放入$source_codeDATA 句柄也将恢复到调用此 sn-p 之前的相同状态。

这应该可以很好地处理如何在不使用源过滤器的情况下读取源文件的问题。

【讨论】:

    猜你喜欢
    • 2013-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    相关资源
    最近更新 更多