【问题标题】:perl: handle die before the frameworkperl:在框架之前处理死
【发布时间】:2012-02-21 16:32:45
【问题描述】:

我正在使用一个监控 $SIG{DIE} 本身的 perl 框架,我的代码是由框架执行的,所以我的异常处理代码无法执行,因为框架是第一个被检测到的然后异常终止脚本。

frame.pm

sub execute
{
  $SIG{__DIE__}         = \&_handleDie;

  eval{  #execute myscript.pl sub main  
         $rv = &$pFunct(@args);}

  if ($@){ processException($@)}

  print "myscript.pl success executed"           

}

myscript.pl

use frame;
frame->execute( \&main );

sub main
{ 
   %codes that redirect STDOUT to a file% 

   #if below API cmd no exception, hide it's output, 
   #otherwise output the API cmd STDERR msg

   %codes called API of another module%


   try
    {
        die("sth wrong");
    }catch{
        %codes restore STDOUT to terminal% 
        print "error msg, but this line will not be executed, how to get it be execute?"
    }
}

脚本首先将 STDOUT 重定向到一个文件,以实现一些无用的输出。

当我想要实现的是如果发生异常(死线),脚本可以将 STDOUT 恢复到终端,然后将错误打印到终端。现在它是由帧处理并打印到 STDOUT 但不是 STDERR,所以我需要在帧打印到 STDOUT 之前处理恢复 STDOUT。

使用ruakh的解决方案,myscript.pl已经通过了帧的SIG,现在被帧行捕获 if ($@){ processException($@)}, 即执行myscript->die()时,程序来到frame->if ($@){ processException($@)},而不是myscript->catch

======================

我终于发现这对我有用:

myscript.pl

frame->execute( \&main );

sub main
{
    open my $stdOri, ">&STDOUT";
    my $tmpFile = "/tmp/.output.txt.$$";
    open STDOUT, ">$tmpFile";

    #overwrite frame provided exception handling.
    local $SIG{__DIE__}=sub{close STDOUT;  open STDOUT, ">&", $stdOri;};

    #cause a exception, 
    #this exception will be processed by 'local $SIG{__DIE__}' block which restore STDOUT
    #then frame->eval catch this exception, and print it in the terminal.
    my $c=5/0;

}

感谢 ruakh 的启发。

【问题讨论】:

  • Re: “当我想要实现的是如果发生异常(死线),脚本可以将 STDOUT 恢复到终端,然后将错误打印到终端”:为什么不只打印到 STDERR 而不是 STDOUT? STDERR 也被重定向了吗?

标签: perl exception try-catch


【解决方案1】:

假设您不想修改框架,您可以在本地覆盖信号处理程序:

use frame;
frame->execute( \&main );

sub main
{
   try
    {
        local $SIG{__DIE__}; # remove signal-handler
        die("sth wrong");
    }catch{
        print STDERR "error msg";
        die $@; # pass control back to framework's signal handler
    }
}

免责声明:使用eval-block 进行测试,而不是使用try/catch,因为我没有安装TryCatch。我的理解是TryCatch 依赖于eval,而不是$SIG{__DIE__},但我可能错了。

【讨论】:

  • 本地 $SIG{DIE} 传递了框架 \&_handleDie,但接下来的例程返回到框架块:if ($@) {exit 1}。是否可以在框架 if($@) 块之前插入我的代码?
  • @brike:对不起,我不明白你想问什么。你是说,即使使用上面的代码,框架的信号处理程序也会在你的 catch 块之前运行?
  • 是的,frame.pm 结构是这样的:init(#setSIG{DIE}); eval($cmdScriptPassed);if($@){processException}。您的解决方案通过了 init(),现在脚本被困在 if($@)block 中。
  • @brike:对不起,我还是不明白你在说什么。也许您应该编辑原始问题以添加此信息。
  • 感谢您的时间和知识,我已经修改了我的问题。
【解决方案2】:

框架的$SIG{__DIE__}处理程序错错错了。它不应该在eval 内吃异常。它应该按照perldoc -f die 的建议执行die @_ if $^S

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-04
    • 2013-11-27
    • 1970-01-01
    • 2023-03-04
    • 2023-03-25
    • 2014-04-05
    • 2020-09-02
    相关资源
    最近更新 更多