2012-08-30 16 views
9

Giả sử tôi có một chức năng như dưới đây, làm cách nào để nắm bắt đầu ra của cuộc gọi Process.spawn? Tôi cũng có thể giết quá trình này nếu mất nhiều thời gian hơn thời gian chờ đã chỉ định.Quá trình con ngả với thời gian chờ và ngõ ra chụp

Lưu ý rằng chức năng cũng phải là nền tảng chéo (Windows/Linux).

def execute_with_timeout!(command) 
    begin 
    pid = Process.spawn(command)  # How do I capture output of this process? 
    status = Timeout::timeout(5) { 
     Process.wait(pid) 
    } 
    rescue Timeout::Error 
    Process.kill('KILL', pid) 
    end 
end 

Cảm ơn.

Trả lời

12

Bạn có thể sử dụng IO.pipe và yêu cầu Process.spawn sử dụng đầu ra được chuyển hướng mà không cần đá quý bên ngoài.

Tất nhiên, chỉ bắt đầu với Ruby 1.9.2 (và cá nhân tôi khuyên 1.9.3)

Sau đây là một việc thực hiện đơn giản bằng cách sử dụng Spinach BDD nội bộ để nắm bắt cả hai ra ngoài và sai lầm đầu ra:

# stdout, stderr pipes 
rout, wout = IO.pipe 
rerr, werr = IO.pipe 

pid = Process.spawn(command, :out => wout, :err => werr) 
_, status = Process.wait2(pid) 

# close write ends so we could read them 
wout.close 
werr.close 

@stdout = rout.readlines.join("\n") 
@stderr = rerr.readlines.join("\n") 

# dispose the read ends of the pipes 
rout.close 
rerr.close 

@last_exit_status = status.exitstatus 

Nguồn ban đầu là ở features/support/filesystem.rb

Rất khuyên bạn đọc tài liệu riêng của Ruby Process.spawn.

Hy vọng điều này sẽ hữu ích.

PS: Tôi đã tạm dừng triển khai thời gian chờ làm bài tập về nhà cho bạn ;-)

+0

Hoàn hảo! Chính xác những gì tôi đã sau và thanh lịch hơn nhiều so với giải pháp của tôi :) – thegreendroid

+0

Cái quái gì '_,' có nghĩa là trong mã đó? –

+3

@TamerShlash đọc tài liệu 'Process.wait2', nó trả về một tuple (hai giá trị), và chúng ta gán một giá trị cho' status' và cái kia (cái đầu tiên) được gán cho _, đó là thực tế phổ biến khi bạn muốn loại bỏ một giá trị. –

3

Tôi đã theo lời khuyên của Anselm trong bài đăng của anh ấy trên diễn đàn Ruby here.

Chức năng trông như thế này -

def execute_with_timeout!(command) 
    begin 
    pipe = IO.popen(command, 'r') 
    rescue Exception => e 
    raise "Execution of command #{command} unsuccessful" 
    end 

    output = "" 
    begin 
    status = Timeout::timeout(timeout) { 
     Process.waitpid2(pipe.pid) 
     output = pipe.gets(nil) 
    } 
    rescue Timeout::Error 
    Process.kill('KILL', pipe.pid) 
    end 
    pipe.close 
    output 
end 

này không được công việc, nhưng tôi muốn sử dụng một viên ngọc của bên thứ ba kết thúc tốt đẹp chức năng này. Bất cứ ai có cách nào tốt hơn để làm điều này? Tôi đã thử Terminator, nó thực hiện chính xác những gì tôi muốn nhưng nó dường như không hoạt động trên Windows.