2012-08-02 51 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