2010-06-03 75 views
6

我在perl中創建了一個腳本,以超時運行程序。如果正在執行的程序需要更長的時間,則超出腳本的超時時間將終止該程序並返回消息「TIMEOUT」。在perl中重定向輸出時,fork exec會出現問題

該腳本工作得很好,直到我決定重定向執行的程序的輸出爲止。

當stdout和stderr被重定向時,腳本執行的程序不會被終止,因爲它的pid與我從fork中獲得的pid不同。

看來perl在重定向的情況下執行一個執行我的程序的shell。

我想要輸出重定向,但仍然能夠在超時的情況下殺死程序。

關於如何做到這一點的任何想法?

我的劇本的簡化代碼:

#!/usr/bin/perl 

use strict; 
use warnings; 
use POSIX ":sys_wait_h"; 

my $timeout = 5; 
my $cmd = "very_long_program 1>&2 > out.txt"; 

my $pid = fork(); 
if($pid == 0) 
{ 
    exec($cmd) or print STDERR "Couldn't exec '$cmd': $!"; 
    exit(2); 
} 
my $time = 0; 
my $kid = waitpid($pid, WNOHANG); 
while ($kid == 0) 
{ 
    sleep(1); 
    $time ++; 
    $kid = waitpid($pid, WNOHANG); 
    print "Waited $time sec, result $kid\n"; 
    if ($timeout > 0 && $time > $timeout) 
    { 
     print "TIMEOUT!\n"; 
     #Kill process 
     kill 9, $pid; 
     exit(3); 
    } 
} 

if ($kid == -1) 
{ 
    print "Process did not exist\n"; 
    exit(4); 
} 
print "Process exited with return code $?\n"; 
exit($?); 

感謝您的幫助。

回答

11

嘗試從

my $cmd = "very_long_program 1>&2 > out.txt"; 

改變$cmd

my $cmd = "exec very_long_program 1>&2 > out.txt"; 

exec會告訴得到由perl的催生與very_long_program替換本身,而不是作爲一個孩子very_long_program運行外殼程序。

(Perl的原因產卵在這種情況下,殼是因爲$cmd包含重定向字符 - 和Perl不知道如何處理他們自身解決問題的另一種方法是做在Perl本身重定向後在fork()但在此之前調用exec() - 但這是稍微麻煩,所以先試試exec解決方法)

+0

!聰明,乾淨和工作。韓國社交協會。 – Edu 2010-06-03 11:41:32

2

另一種方法是叉後stdout和stderr重定向和不重定向運行命令:

open(STDOUT, ">", "out.txt") or die "Err: $!"; 
open(STDERR, ">&STDOUT"); 
exec("very_long_command"); 
die "Failed to exec very_long_command: $!";