2012-08-02 52 views
5

我有一个简单的Perl脚本,它只是将一行文本打印到stdout。我想要完成的是当脚本运行时,如果我(或其他人)发出一个信号让该进程停止,我希望它捕获该信号并干净地退出。我的代码如下所示干净地在Perl中捕获信号

#!/usr/bin/perl -w 

$| = 1; 
use sigtrap 'handler' => \&sigtrap, 'HUP', 'INT','ABRT','QUIT','TERM'; 
while(1){ 
print "Working...\n"; 
sleep(2); 
} 
sub sigtrap(){ 
print "Caught a signal\n"; 
exit(1); 
} 

虽然这个效果很好,当我真正在命令行中按Ctrl-C,如果我发出了一个

kill -9 <pid> 

它只是死亡。如何在退出前执行某些操作?我的一般想法是使用此框架来捕获此脚本因服务器重新启动以进行维护或故障而死于服务器时。

感谢很多提前

回答

11

Signal#9(SIGKILL)不能被困住。这就是Unix的设计。

但是,系统在关闭维护时不发送该信号。至少你的守护进程的行为是否正确。它通常会发送TERM信号(或者更准确地说,您的守护进程处理脚本在/etc/init.d中所做的)。只有在超时后没有正确关闭的进程才会收到SIGKILL。

因此,您的目标应该是正确处理TERM信号并编写/etc/init.d中的包装脚本,当系统更改运行级别时将调用该脚本。

更新:您可以使用Daemon::Control模块作为init脚本。

4

你发送两个非常不同的信号到你的进程。在控制台中按Ctrl-C通常会发送进程a TERM INT信号,通过您的代码判断 - 被捕获并提供服务。然而,kill -9明确地发送了号码9,其被称为KILL。这是其服务不能被重新定义的信号之一,并且该信号的传送总是立即结束由内核本身完成的过程。

+3

按下'Ctrl-C'发送'INT'信号**不是**'TERM',但默认动作如果对于一个交互过程是相同的。无论哪种信号都可以被捕获,不像'kill -9'。 'kill -l'将列出信号名称。 'stty -a'将显示'INT'到'Ctrl-C'的默认映射。 – JRFerguson 2012-08-03 11:44:25

+0

哎唷!感谢您清除错误并为错误信息而感到抱歉。 – 2012-08-06 05:51:28

3

据我所知,你不能捕获kill -9。改为尝试kill <pid>

+2

这将提供一个'TERM',这实际上等同于在控制台中按下“Ctrl-C”。 – 2012-08-02 22:03:10

+0

@DanielKamilKozar谢谢,很高兴知道。 – 2012-08-02 22:05:12

+3

@DanielKamilKozar:按下'Ctrl-C'发送'INT'信号**不是**'TERM',虽然默认动作如果对于一个交互过程是相同的。无论哪种信号都可以被捕获,不像'kill -9'。 'kill -l'将列出信号名称。 'stty -a'将显示'INT'到'Ctrl-C'的默认映射。 – JRFerguson 2012-08-03 11:45:06