【问题标题】:Prevent Perl from printing identical warning messages防止 Perl 打印相同的警告消息
【发布时间】:2012-04-03 21:35:39
【问题描述】:

以下面的废话脚本为例:

use strict;
use warnings;

my $uninitialisedValue;

while(<>){
  print ${$uninitialisedValue}{$_},"\n";
}

从命令行运行:

$ perl warningPrinter.pl < longfile.txt

无论标准输入包含什么,标准输出都会充满:

Use of uninitialized value in print at warningPrinter.pl line 16, <> line 1.

Use of uninitialized value in print at warningPrinter.pl line 16, <> line 2.

Use of uninitialized value in print at warningPrinter.pl line 16, <> line 3.

Use of uninitialized value in print at warningPrinter.pl line 16, <> line 4.
...

我使用非常长的文件,因此在测试我的脚本时将其作为输出接收至少会有点烦人。进程响应 Ctrl + C 终止信号可能需要一段时间,并且我的终端突然充满了相同的错误消息。

有没有办法让 Perl 只打印相同且重复出现的警告消息的第一个实例,或者只使警告消息对脚本的执行造成致命影响?鉴于尽管有警告,但我从未制作过有效的脚本,所以我会接受。但如果我能让 Perl 只打印一次相同的警告,可能会更方便。

【问题讨论】:

  • 试试这个 StackOverflow 的另一个帖子:[How can I make Perl die if a warning is generated?][1] [1]: stackoverflow.com/questions/3896060/…
  • 优秀。 use warnings FATAL =&gt; 'all' 非常适合在我收到警告后终止进程。
  • 在读取文件时不要使用for,尤其是当文件很大时,因为 for 循环会将其列表预加载到内存中。请改用while。此外,将文件重定向到标准输入是多余的,只需使用文件作为参数。在您的特定问题中,将 STDERR 重新打开到文件可能是一种解决方案。
  • 哦,糟糕,我的意思是while :p。但是,我发现从 STDIN 读取代码更快,并且脚本将自动与来自另一个进程的管道兼容。如果我只是从命令行获取一个参数,我将不得不检查用户是否真的想从 STDIN 读取。
  • @kikumbob 菱形运算符适用于 STDIN 或文件参数。你的区分是无效的。使用script.pl &lt; filescript.pl file 与使用菱形运算符&lt;&gt; 时相同。

标签: perl warnings


【解决方案1】:

我想我会向您展示如何创建独特的警告逻辑。不过我不推荐它:

my %printed;
local $SIG{__WARN__} = sub { 
    my $message = shift;
    my ( $msg, $loc ) = $message =~ m/(.*?) at (.*?line \d+)/;
    print $message unless $printed{$loc}{$msg}++;
};

我应该说我不建议将其作为一般的做法。因为最好有一个警告政策。它要么是一个可以采用未定义值的操作,要么是您不想处理 undef 值。我尝试从已完成的代码中删除所有警告。

在第一种情况下,将no warnings 'uninitialized'; 放入for 循环是一件容易得多的事情——而且是常规。在第二种情况下,您可能希望失败。

但是,如果这是您真正想要处理但警告过一次的事情,假设您想要对数据进行稳健处理,但想要警告上游进程您有一些不良数据,您可以创建一个 @ 987654325@:

{   use Carp ();
    my %warned;
    sub warn_once { 
        my $message = shift;
        my ( $msg, $loc ) = $message =~ m/(.*?) at (.*?line \d+)/;
        Carp::carp( $message ) unless $warned{$loc}{$msg}++;
    };
}

然后这样称呼它:

while ( <> ) { 
    warn_once( '$uninitialisedValue is uninitialized' )
        unless defined( $uninitialisedValue)
        ;
    no warnings 'uninitialized';
    print ${$uninitialisedValue}{$_},"\n";
}

那么你已经决定了一些事情。

【讨论】:

  • 不错!我想我必须在我想使用这个逻辑的每个脚本中添加这种东西?为什么不推荐呢?
  • @kikumbob 我会在我的帖子中详细说明。
  • 请注意,diagnostics 模块会完成所有这些工作,除了考虑输入块的行号的部分。
猜你喜欢
  • 2022-01-11
  • 2013-05-12
  • 2022-08-21
  • 1970-01-01
  • 1970-01-01
  • 2018-08-07
  • 2012-10-27
  • 2010-11-06
  • 2021-03-25
相关资源
最近更新 更多