2012-11-09 44 views
5

我正在使用Term :: ReadLine :: Gnu,并遇到信号处理问题。给定下面的脚本和发送给脚本的TERM信号,TERM信号的处理程序不会被触发,直到后面的按下回车键。使用Term :: ReadLine:Perl不会发生。Perl术语:: ReadLine :: Gnu信号处理难点

我读过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处理程序,而不是等待按下Enter键。

任何帮助或建议当然赞赏!

#!/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"; 
    } 
} 
+0

我不知道这是否是一个缓冲问题。尝试从这个答案的解决方案:http://stackoverflow.com/a/7603502/1791055 – titanofold

+1

什么是\/S || \ n /'应该做的? :-)(与你的实际问题无关,我只注意到它)。请注意,因为你的两个管道之间没有任何东西,所以正则表达式会匹配任何东西,所以!〜将永远是错误的。 – Tanktalus

+0

ysth帮助我在另一篇文章中回答这个问题http://stackoverflow.com/questions/13332908/termreadline-i-need-to-hit-the-up-arrow-twice-to-retrieve-history 原来它是完全的多余的T:R:G默认为添加历史。我会删除它。 –

回答

3

这是由于Perl的默认的信号处理偏执 - 在幕后,Perl的块SIGTERM开始readline呼叫之前,当它完成恢复它。有关详细信息,请参阅Deferred Signals in perlipc

Term::ReadLine::Perl使用perl的IO,它知道这些问题并处理它们,所以你不会看到这个bug。 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了解详情。