使用标志进行 Perl 调试

3

我的目标是找到一种简单的方法,在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

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

2
你也可以考虑使用环境变量:DEBUG=1 perl perlScript.pl。然后,你可以检查 DEBUG 环境变量($ENV{DEBUG}),并根据需要做出反应。 - Hunter McMillen
5个回答

3
在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;
}

这更多是取决于我正在编写的代码类型 - 当我做一些 fork 相关的工作时,我特别喜欢这种方式,因为这样我可以独立地在每个 fork 中即时调整调试级别。


我使用了GetOptions来处理我的命令选项。如果用户输入了“-debug”标志,有没有办法让$debug = 1?因为现在我首先将$debug = 0,然后执行GetOptions(debug=i =>$debug)。问题是,如果他们只输入了“-debug”,那么$debug仍然被设置为0...但是如果他们没有包含详细设置,我希望它被设置为1。 - user1334858
由于某些原因,grep ("-d", @ARGV) 对我没有作用,它只给了我参数的总数。为了计算传递的-d参数数目,我必须使用 grep(/-d/, @ARGV)。也就是说要使用 / 而不是 ". 这是在假设您使用 script.pl -d -d filename.txt 调用脚本来获得调试级别为2的情况下。或者我是否误解了脚本的调用方式(当使用grep("-d"...)时,即如何使用参数触发调试? - Greenonline
怎样在这之后从 ARGV 中省略 -d - undefined
@rustyx 可能更好的做法是将其作为一个问题提出,但你可以使用 grep 来过滤 @ARGV。例如,@ARGV = grep { ! /^-d$/ } @ARGV - undefined

2
-s选项允许您在命令行上指定main包变量的值,但您必须从文件运行perl程序,而不是使用-e选项。如果您有一个perl程序:
use strict;
use warnings;

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

并通过命令行运行它

perl -s myprog.pl -debug

然后程序将打印1

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

#!/usr/bin/perl -s

use strict;
use warnings;

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

然后你的命令行只需包含以下内容。
myprog.pl -debug

我尝试使用-s选项,但它并没有按照你说的那样工作。我需要使用use strictuse warnings吗?我正在使用GetOptions来获取-debug标志。 - user1334858
@user1334858:-debug 参数必须在脚本文件名之后,任何参数之前。因此,如果您将文件 f1f2 传递给您的脚本,则应编写 perl -d myscript.pl -debug f1 f2。如果它正常工作,则 -debug 将从 @ARGV 中删除,并且 GetOptions 永远不会看到它。您应该首先尝试使用我上面提供的程序,看看是否可以使其打印值为 1,然后再根据您的需求进行调整。 - Borodin
今天学到了有关Perl的新知识。 - mob

1
我通常使用以下样板来通过 Log::Log4perl 记录脚本的日志。您可以在命令行上覆盖 logbase/log 配置位置(或者更通常地,在部署时设置适当的位置作为默认值),并在向脚本提供一个或多个 -verbose 标志时,覆盖该日志并记录到屏幕上,其中 4 个 verboses 可以使您获得屏幕输出。这使您可以轻松地从通过提供详细标志进行调试转换,以获得每个日志输出,然后将其传递给自定义日志处理程序配置以调试子系统,最后在生产部署中设置日志记录,所有这些都只需要最小/没有代码更改。
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});
}

1
与您的想法类似,但更为简洁,会输出到stderr,并假设您使用类似Getopt::Long的东西来设置调试CLI选项。
warn "debug info:..." if ( $debug );

问题是关于如何首先设置$debug的。 - Borodin

-2

在v5.10之前,您还可以使用C预处理器对Perl脚本进行文字处理,方法是使用命令行开关-P,详见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开关)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接