代码之家  ›  专栏  ›  技术社区  ›  Matthew Watson

如何在Perl中找到print语句的源位置?

  •  9
  • Matthew Watson  · 技术社区  · 17 年前

    如何在Perl中找到print语句的源位置?

    #!/usr/bin/perl
    
    foo();
    bar();
    
    sub foo {
      print "foo\n";
    }
    
    sub bar {
      print "bar\n";
    }
    

    输出为:

    >perl test.pl 
    foo
    bar
    

    我想不知何故地找到能够看见(或类似的东西)

    >perl test.pl 
    main::foo> foo
    main::bar> bar
    

    原因是我正试图跟踪一些胭脂红输出,但在大型代码库中找不到它的位置。

    8 回复  |  直到 12 年前
        1
  •  15
  •   hexten    17 年前

    试试这个:

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    use Tie::STDOUT print => sub {
      my ( $pkg, $file, $line ) = caller(2);
      print "$pkg, $file, $line :: ", @_;
    };
    
    print "Hello, World\n";
    

    它给出:

    $ perl tp.pl
    main, tp.pl, 10 :: Hello, World
    

    更新:我刚刚发布 Devel::Ditto :

    $ perl -MDevel::Ditto myprog.pl
    [main, t/myprog.pl, 9] This is regular text
    [main, t/myprog.pl, 10] This is a warning
    [MyPrinter, t/lib/MyPrinter.pm, 7] Hello, World
    [MyPrinter, t/lib/MyPrinter.pm, 8] Whappen?
    
        2
  •  8
  •   Suic    12 年前

    使用调试::跟踪( https://metacpan.org/pod/Debug::Trace )

    #!/usr/bin/perl
    
    foo();
    bar();
    
    sub foo {
      print "foo\n";
    }
    
    sub bar {
      print "bar\n";
    }
    

    此程序保存为test.pl并调用为:

    perl -MDebug::Trace=foo,bar test.pl
    

    打印输出:

    TRACE:  main::foo() called at test.pl line 3 package main
    foo
    TRACE:  main::foo() returned
    TRACE:  main::bar() called at test.pl line 4 package main
    bar
    TRACE:  main::bar() returned
    
        3
  •  5
  •   Sinan Ünür    17 年前

    我知道源过滤器可以用于以下用途:

    C:\Temp> cat DebugFilter.pm
    package DebugFilter;
    
    use strict;
    use warnings;
    
    use Filter::Simple;
    
    FILTER_ONLY
        code_no_comments => sub {
            s/print/main::mydebugfn();print/g
        };
    
    1;
    __END__
    
    C:\Temp> cat DebugPrint.pm
    package DebugPrint;
    
    use strict;
    use warnings;
    
    use base qw( Exporter );
    
    our @EXPORT = qw( mydebugfn );
    
    sub mydebugfn {
        my ( $pkg, $fn, $line, $sub ) = caller(2);
        warn "print called from: ${sub}(${fn}:${line})\n";
    }
    
    1;
    __END__
    
    C:\Temp> cat t.pl
    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use DebugFilter;
    
    sub test {
        print STDOUT "print in test\n";
        return;
    }
    
    test();
    

    以下是输出:

    C:\Temp> perl -MDebugPrint t.pl
    print called from: main::test(t.pl:13)
    print in test
    
        4
  •  4
  •   Bron Gondwana    17 年前

    Copas:我不能直接回复你的评论(还不够“酷”),但基本问题是任何一个合适的项目都不是一个.pl文件。它是一组模块,所有模块都被拉到一起。

    您的代码:

    a)不处理one.pl文件之外的任何内容 b)不处理打印(…)有括号或间距不同的情况。 c)不处理第一个要打印的参数是函数调用或变量而不是双引号字符串的情况。 d)考虑:$object->日志(“AM即将打印”。FO($var)。到控制台);-您的regex将导致语法错误,使其成为:$object->日志(“am about to print”第1084行:。$FO($var)。至控制台);

    也就是说,它对于简单的脚本是可行的。这不是一个坏主意(最坏的情况是,newsource.pl不编译),但除非全部在一个文件中,否则它不会解决这个特定的问题。

        5
  •  4
  •   Community Mohan Dere    9 年前

    本文解释了如何钩住perl print函数: How can I hook into Perl's print?

    如果不想用其他东西替换源代码中的所有print语句,则可能需要它。

        6
  •  4
  •   Sinan Ünür    17 年前

    我将保留源过滤器选项以供参考,因为它面向跟踪单个函数的调用。

    然而,解决方案似乎是使用 Devel::Trace . 这可能会生成大量输出,您可以将其重定向到一个文件,然后对有问题的输出进行grep。

    C:\Temp> perl -d:Trace t.pl
    >> t.pl:10: T::test();
    >> T.pm:5:     print "in T::test\n";
    in T::test
    >> c:/opt/perl/lib/Config.pm:63: sub DESTROY { }
    
        7
  •  3
  •   Mike Tunnicliffe    17 年前

    您可以尝试使用调试器(perl-d)单步执行代码。

    我建议覆盖打印并使用:

    ($package, $filename, $line) = caller;
    

    …打印出额外的信息,但事实证明,打印是不能被覆盖的内置功能之一。

        8
  •  1
  •   singingfish    17 年前

    你可以尝试使用 Hook::LexWrap 深入研究代码库中的内容。它在内部做了一些非常邪恶的事情,所以不适用于所有代码库。