2014-01-20 75 views
3

我瀏覽並閱讀了一些其他有關在一段時間後命令停止運行的問題,但是我嘗試的所有操作都無效。無法使系統命令在perl腳本中超時

該命令將在指定的時間量後停止運行(它會在短暫的時間內返回終端提示符),但只會繼續運行並不會停止。

這裏是我的代碼:

#!/usr/bin/perl 

use strict; 
use warnings; 


use Try::Tiny; 

try { 
     local $SIG{ALRM} = sub { die "alarm\n" }; 
     alarm 5; 
     system("ping 192.168.1.1"); 
     alarm 0; 
} 
catch { 
     die $_ unless $_ eq "alarm\n"; 
     print "timed out\n"; 
}; 
exit; 

在終端的輸出是這樣的:

PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data. 
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=1.98 ms 
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=3.13 ms 
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=3.20 ms 
64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=3.17 ms 
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=3.16 ms 
64 bytes from 192.168.1.1: icmp_seq=6 ttl=64 time=3.11 ms 
64 bytes from 192.168.1.1: icmp_seq=7 ttl=64 time=3.18 ms 
64 bytes from 192.168.1.1: icmp_seq=8 ttl=64 time=3.20 ms 
64 bytes from 192.168.1.1: icmp_seq=9 ttl=64 time=3.22 ms 
64 bytes from 192.168.1.1: icmp_seq=10 ttl=64 time=3.20 ms 
[email protected]:~/perlstuff$ 64 bytes from 192.168.1.1: icmp_seq=11 ttl=64 time=3.06 ms 
64 bytes from 192.168.1.1: icmp_seq=12 ttl=64 time=3.19 ms 
64 bytes from 192.168.1.1: icmp_seq=13 ttl=64 time=3.21 ms 
64 bytes from 192.168.1.1: icmp_seq=14 ttl=64 time=3.21 ms 

注意它是如何試圖阻止,但不能。

+0

您是否已在'catch'塊中打印'$ _'? – simbabque

+0

它在Windows上爲我打印'超時\ n',但隨後繼續執行。有趣。 – simbabque

+0

是的,它只是在提示符上打印「警報」一秒鐘,然後繼續。 –

回答

4

perl'system'內建函數分叉你的進程,並且在由fork創建的子進程中,它執行'ping'程序。然後,父進程等待子進程完成。

您的警報計時器和信號處理程序中斷等待進程,然後終止父進程,使子進程在後臺運行。

什麼,你需要做的是:

  1. 後報警超時,通過發送一個信號
  2. 您應該仍然(手動)的過程中等待殺子進程,以避免收到一個殭屍。

試試這個:

#!/usr/bin/perl 

use strict; 
use warnings; 



eval { 
     local $SIG{ALRM} = sub { die "alarm\n" }; 
     alarm 5; 
     system("ping -v 192.168.1.1"); 
     alarm 0; 
}; 
if ([email protected]) { 
     die [email protected] unless [email protected] eq "alarm\n"; 
     print "timed out\n"; 
     kill 2, -$$; 
     wait; 
}; 
exit; 

注:我沒有嘗試::微型我的系統上,所以我取代了老派的eval塊。但它應該是一樣的。

這個'kill'命令需要一個信號編號(我使用2作爲SIGINT,相當於按ctrl-c)和一個或多個進程終止。 $$是當前進程的pid;負值具有殺死與當前進程相關的整個進程組的效果(這實際上意味着所有子進程)。請注意,這不是完全可移植的 - 如果您發現它不適用於您的系統,那麼您將需要能夠找到子進程的實際PID。爲了能夠做到這一點,你應該更換系統與調用叉,然後執行,如下所示:

#!/usr/bin/perl 

use strict; 
use warnings; 


my $childPid; 
eval { 
     local $SIG{ALRM} = sub { die "alarm\n" }; 
     alarm 5; 
     if ($childPid = fork()) { 
       wait(); 
     } else { 
       exec("ping -v 192.168.1.1"); 
     } 
     alarm 0; 
}; 
if ([email protected]) { 
     die [email protected] unless [email protected] eq "alarm\n"; 
     print "timed out\n"; 
     kill 2, $childPid; 
     wait; 
}; 
exit; 
+0

您的第二個解決方案適用於我。 –