Perl Term :: ReadLine :: Gnu信号处理的难点

时间:2012-11-09 21:23:13

标签: perl readline signal-handling

我正在使用Term :: ReadLine :: Gnu并遇到信号处理问题。鉴于下面的脚本和发送到脚本的TERM信号,在按下回车键之后,才会触发TERM信号的处理程序。使用Term :: ReadLine:Perl不会发生这种情况。

我读过Term :: ReadLine :: Gnu有自己的内部信号处理程序,但坦率地说,我对如何使用它们感到茫然。

我已经审核了http://search.cpan.org/~hayashi/Term-ReadLine-Gnu-1.20/Gnu.pm#Term::ReadLine::Gnu_Variables尝试将rl_catch_signals变量设置为0,但这没有帮助。理想情况下,我想与Gnu信号处理程序一起工作,但我也会满足于禁用它们。

绝对具体,我需要在收到信号后触发TERM处理程序,而不是等待按下回车键。

当然感谢任何帮助或建议!

#!/usr/bin/perl

use strict;
use warnings;
use Term::ReadLine;

$SIG{TERM} = sub { print "I got a TERM\n"; exit; };

my $term = Term::ReadLine->new('Term1');
$term->ornaments(0);
my $prompt = 'cmd> ';
while ( defined (my $cmd = $term->readline($prompt)) ) {
    $term->addhistory($cmd) if $cmd !~ /\S||\n/;
    chomp($cmd);
    if ($cmd =~ /^help$/) {
        print "Help Menu\n";
    }
    else {
        print "Nothing\n";
    }
}

1 个答案:

答案 0 :(得分:3)

这是由于perl对信号的默认偏执处理 - 在幕后,perl在开始readline调用之前阻塞SIGTERM并在完成后恢复它。有关详细信息,请参阅Deferred Signals in perlipc

Term::ReadLine::Perl使用perl的IO,它知道这些问题并处理它们,所以你没有看到它的错误。 Term::ReadLine::Gnu使用的是C库,但不是这样。

您可以使用以下两种方法之一解决此问题:

  1. 在运行脚本之前将环境变量PERL_SIGNALS设置为unsafe,如下所示:

    bash$ PERL_SIGNALS=unsafe perl readline-test.pl
    

    注意,BEGIN { $ENV{PERL_SIGNALS} = "unsafe"; }是不够的,需要在perl本身启动之前设置它。

  2. 使用POSIX信号函数:

    #~ $SIG{TERM} = sub { print "I got a TERM\n"; exit; };
    use POSIX;
    sigaction SIGTERM, new POSIX::SigAction sub { print "I got a TERM\n"; exit; };
    

    以上两者似乎都适用于Linux;不能代表Windows或其他unices。此外,上述两种情况都存在风险 - 详见perlipc。