【问题标题】:Perl Debugging Using Flags使用标志进行 Perl 调试
【发布时间】:2015-09-09 13:31:03
【问题描述】:

所以我的目标是找到一种使用标志在 Perl 中打开打印语句的简单方法。在 C/C++ 中,您可以使用 #define 来选择是否运行某些代码,这是一种打开和关闭调试打印语句的方法。如果定义了#define DEBUG,那么你打印一些东西,否则你在没有打印语句的情况下运行它。我想知道在 Perl 中是否有一种简单的方法可以做到这一点。

这是一个如何工作的示例:

for($i = 0 ; $i < 10; $i++){
    if(debug flag){
         print some info;
    }
    do operational stuff.
}

现在,您可以从命令行执行以下两项操作之一:

1.在没有调试打印语句的情况下运行

perlScript.pl 

2.运行调试打印语句

perlScript.pl -debug

或者如果有人有更好的想法,请告诉我!

【问题讨论】:

  • 您也可以考虑使用环境变量:DEBUG=1 perl perlScript.pl。然后你可以检查 DEBUG 环境变量($ENV{DEBUG})并做出相应的反应

标签: perl debugging script-debugging


【解决方案1】:

-s 选项允许您在命令行上指定 main 包变量的值,但您必须从文件运行 perl 程序而不是使用 -e 选项

如果你有 perl 程序

use strict;
use warnings;

our $debug
print $debug, "\n";

用命令行运行

perl -s myprog.pl -debug

然后程序将打印1

请注意,您可以在程序文件本身的 shebang 行中指定它,而不是在命令行上使用 -s,所以如果您的代码看起来像

#!/usr/bin/perl -s

use strict;
use warnings;

our $debug
print $debug, "\n";

那么你的命令行只需要包含

myprog.pl -debug

【讨论】:

  • 我尝试使用 -s... 它没有按照你说的那样做。我需要use strictuse warnings 吗?我使用 GetOptions 作为获取 -debug 标志的方式
  • @user1334858:-debug 必须在脚本文件名之后和脚本的任何参数之前。因此,如果您将文件f1f2 传递给您的脚本,您将编写perl -d myscript.pl -debug f1 f2。如果它工作正常,那么-debug 将从@ARGV 中删除,GetOptions 将永远看不到它。你应该先用我上面的程序试试,看看你能不能让它打印出值 1,然后根据你的需要调整它。
  • 今天学习了一些关于 Perl 的新知识。
【解决方案2】:

在 v5.10 之前,您还可以通过 -P 命令行开关在您的 Perl 脚本上使用 C 预处理器,记录在 perlrun 中。

#!perl -P
# myScript.pl
#define DEBUG(x) x
$foo = 42;
DEBUG( print "foo is $foo\n"; )

$ perl -P myScript.pl
foo is 42

(就像-T 开关一样,#!perl -P 不会自动将 C 预处理器与您的脚本一起使用,但它确实会强制您在每次运行脚本时自己显式使用 -P 开关)

【讨论】:

    【解决方案3】:

    我通常使用以下样板通过Log::Log4perl 登录脚本。您可以从命令行覆盖日志库/日志配置位置(或者,更常见的是,在部署时将适当的位置设置为默认位置),并在为脚本提供一个或多个 -verbose 标志后,覆盖该日志记录并登录到屏幕,使用4 个详细信息为您提供屏幕输出。这使您可以轻松地从调试过渡到通过提供详细标志来获取每个日志输出,将其传递到自定义日志处理程序配置以调试子系统,再到在生产部署中设置日志记录,所有这些都只需极少/无代码更改。

    use Getopt::Long;
    use Pod::Usage;
    use Log::Log4perl qw/:easy/;
    
    my $opts = { logconf        => undef,
                 logbase        => 'corp.team.app.appname'
                 debug          => 0,
               };
    
    GetOptions ( 'logconf|l=s'       => \$opts->{logconf},
                 'logbase=s'         => \$opts->{logbase},
                 'verbose|v+'        => \$opts->{debug},  ### debug levels - 0 = off (default), 1 = error, 2 = warn, 3 = info, 4 = debug.
                                                          ### Ignored if a logconf is provided.
               ) or pod2usage(0);
    
    ### Initialize logging subsystem
    init_logger();
    
    ### Usage
    logger('app_subsystem')->info('some message...');
    logger()->debug('debug message...');
    
    
    ### Initialize logging system
    sub init_logger {
        ### If a log configuration is found, and debug was not set, use it
        if (        $opts->{logconf}
             and -e $opts->{logconf}
             and  ! $opts->{debug}
           ) {
            Log::Log4perl->init($opts->{logconf});
        }
        ### Otherwise fall through to easy_init a screen logger based on the verboseness level
        ### Logging off if no config found and no verboseness set
        else {
            my ($min, $max) = ( 0, 4 );
            my %levels;
            @levels{$min .. $max} = ( $OFF, $ERROR, $WARN, $INFO, $DEBUG );
            my $log_level = $opts->{debug};
            if ($log_level < $min) {
                $log_level = $min;
            }
            elsif ($log_level > $max) {
                $log_level = $max;
            }
            Log::Log4perl->easy_init($levels{$log_level});
        }
    }
    
    ### Shorthand shim sub to get a logger
    ### Always returns a Log::Log4perl logger object
    sub logger {
        my ($category) = @_;
        if ($category) {
            return Log::Log4perl->get_logger($opts->{logbase} . '.' . $category);
        }
        return Log::Log4perl->get_logger($opts->{logbase});
    }
    

    【讨论】:

      【解决方案4】:

      与您的想法类似,但更简洁并转到 stderr 并假设您使用 Getopt::Long 之类的东西来设置调试 CLI 选项。

      warn "debug info:..." if ( $debug );
      

      【讨论】:

      • 问题首先是关于如何设置$debug
      【解决方案5】:

      在 perl 中,编译时间也是运行时间。所以使用#define 类型语句并没有太大的优势。

      我的惯用伎俩是:

      my $debug = 0; 
      $debug += scalar grep ( "-d", @ARGV ); 
      

      (虽然GetOpt 可能确实是一个更好的计划)

      然后使用:

      print if $debug;
      print $statement if $debug > 2;
      

      这意味着我有一种设置详细程度的简单方法,并且还允许我通过增加语句来选择它。

      有时我会嵌入一个信号处理程序来调整调试级别 -

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      
      my $debug = 0; 
      $debug += scalar grep ( "-d", @ARGV ); 
      
      $SIG{'USR1'} = { $debug++ };
      $SIG{'USR2'} = { $debug-- };
      
      while ( 1 ) {
          print "Debugging at: $debug\n";
          sleep 1;
      }
      

      更多的是关于我正在编写什么样的代码的问题——在做forky 的事情时我特别喜欢后者,因为这样我就可以在每个分支中独立且动态地调整调试级别。

      【讨论】:

      • 所以我使用 GetOptions 作为我的命令选项。如果他们放入-debug 标志,有没有办法制作$debug = 1。因为现在我首先设置$debug =0 然后我设置GetOptions(debug=i =&gt;$debug)。问题是如果他们只是做'-debug'然后$debug仍然设置为0....但是如果他们不包含详细设置,我希望它设置为1。
      • 出于某种原因,grep ("-d", @ARGV) 对我不起作用,它只是给了我参数的总数。为了计算传递的-d 参数的数量,我必须使用grep(/-d/, @ARGV)。也就是说使用/ 而不是"。这是假设您使用script.pl -d -d filename.txt 调用脚本,以获得二级调试。还是我误解了脚本的调用方式(使用grep("-d"... 时),即如何使用参数触发调试?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-15
      • 2020-09-13
      • 1970-01-01
      相关资源
      最近更新 更多