Perl Term::ReadLine::Gnu信号处理困难

Perl Term::ReadLine::Gnu信号处理困难,perl,readline,signal-handling,Perl,Readline,Signal Handling,我使用的是Term::ReadLine::Gnu,在信号处理方面遇到了问题。给定下面的脚本和发送到脚本的术语信号,在按下enter键之前不会触发术语信号的处理程序。使用Term::ReadLine:Perl时,不会发生这种情况 我已经读过术语::ReadLine::Gnu有它自己的内部信号处理程序,但坦率地说,我不知道如何使用它们 我已经试过将rl_catch_signals变量设置为0,但没有帮助。理想情况下,我希望使用Gnu信号处理程序,但我也会满足于禁用它们 确切地说,我需要在收到信号后触

我使用的是Term::ReadLine::Gnu,在信号处理方面遇到了问题。给定下面的脚本和发送到脚本的术语信号,在按下enter键之前不会触发术语信号的处理程序。使用Term::ReadLine:Perl时,不会发生这种情况

我已经读过术语::ReadLine::Gnu有它自己的内部信号处理程序,但坦率地说,我不知道如何使用它们

我已经试过将rl_catch_signals变量设置为0,但没有帮助。理想情况下,我希望使用Gnu信号处理程序,但我也会满足于禁用它们

确切地说,我需要在收到信号后触发术语处理程序,而不是等待按下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";
    }
}

这是由于perl对信号的默认偏执处理——在幕后,perl在启动
readline
调用之前阻塞SIGTERM,并在调用完成后将其恢复。有关详细信息,请参阅

Term::ReadLine::Perl
使用Perl的IO,它知道这些问题并处理这些问题,因此您不会看到这个bug<代码>术语::ReadLine::Gnu使用C库,而C库不使用,您也一样

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

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

    bash$ PERL_SIGNALS=unsafe perl readline-test.pl
    
    注意,
    BEGIN{$ENV{PERL_SIGNALS}=“safe”}
    是不够的,需要在PERL本身启动之前设置它

  • 使用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或其他Unice说话。此外,上述两种情况都有风险——详情见perlipc


  • 我想知道这是否是一个缓冲问题。尝试以下答案的解决方案:
    /\S | | \n/
    应该做什么?:-)(与您的实际问题无关,我只是注意到了。)注意,因为您的两个管道之间没有任何内容,所以正则表达式将匹配任何内容,所以!~在另一篇文章中帮助我回答这个问题,结果证明这是完全多余的,因为T:R:G默认添加历史记录。我将删除它。泰坦尼克号-谢谢你的链接。当然很有趣(我会尝试一下),但我不确定这是否适用于这个问题。我认为这更多的是关于T:R:G的内部信号处理。