2010-06-03 21 views
6

Tôi đã tạo một tập lệnh trong perl để chạy các chương trình với thời gian chờ. Nếu chương trình được thực thi mất nhiều thời gian hơn thì thời gian chờ hơn kịch bản sẽ giết chết chương trình này và trả về thông báo "TIMEOUT".Sự cố với lệnh ngắt thực hiện khi chuyển hướng đầu ra trong perl

Kịch bản hoạt động khá tốt cho đến khi tôi quyết định chuyển hướng đầu ra của chương trình đã thực hiện.

Khi stdout và stderr đang được chuyển hướng, chương trình được thực thi bởi tập lệnh sẽ không bị giết vì nó có pid khác với điểm tôi nhận được từ ngã ba.

Có vẻ như perl thực hiện một trình bao thực hiện chương trình của tôi trong trường hợp chuyển hướng.

Tôi muốn có chuyển hướng đầu ra nhưng vẫn có thể giết chương trình trong trường hợp hết thời gian chờ.

Bất kỳ ý tưởng nào về cách tôi có thể làm điều đó?

Một mã đơn giản của kịch bản của tôi là:

#!/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($?); 

Cảm ơn sự giúp đỡ nào.

Trả lời

11

Hãy thử thay đổi $cmd từ

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

để

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

Các exec sẽ cho vỏ mà được sinh ra bởi perl để thay thế chính nó với very_long_program, chứ không phải chạy very_long_program như một đứa trẻ.

(Lý do perl sinh ra một vỏ trong trường hợp này là vì $cmd chứa các ký tự chuyển hướng - và perl không biết cách xử lý chúng. Một cách khác để giải quyết vấn đề là thực hiện chuyển hướng trong chính perl sau các fork() nhưng trước khi gọi exec() - nhưng đó là một chút phức tạp hơn, vì vậy hãy thử các exec workaround đầu tiên)

+0

! Thông minh, sạch sẽ và hoạt động. Tks. – Edu

2

Một cách khác là để chuyển hướng stdout và stderr sau khi ngã ba và chạy lệnh mà không có sự chuyển hướng:

open(STDOUT, ">", "out.txt") or die "Err: $!"; 
open(STDERR, ">&STDOUT"); 
exec("very_long_command"); 
die "Failed to exec very_long_command: $!"; 
Các vấn đề liên quan