Say I have a function like below, how do I capture the output of the Process.spawn call? I should also be able to kill the process if it takes longer than a specified timeout.
假设我有类似下面的函数,如何捕获Process.spawn调用的输出?如果进程花费的时间超过指定的超时时间,我也应该能够终止进程。
Note that the function must also be cross-platform (Windows/Linux).
请注意,该功能还必须是跨平台的(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
Thanks.
谢谢。
2 个解决方案
#1
12
You can use IO.pipe
and tell Process.spawn
to use the redirected output without the need of external gem.
您可以使用IO.pipe并告诉Process.spawn使用重定向输出而无需外部gem。
Of course, only starting with Ruby 1.9.2 (and I personally recommend 1.9.3)
当然,只从Ruby 1.9.2开始(我个人推荐1.9.3)
The following is a simple implementation used by Spinach BDD internally to capture both out and err outputs:
以下是Spinach BDD内部用于捕获out和err输出的简单实现:
# 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
The original source is in features/support/filesystem.rb
原始源位于features / support / filesystem.rb中
Is highly recommended you read Ruby's own Process.spawn documentation.
强烈建议您阅读Ruby自己的Process.spawn文档。
Hope this helps.
希望这可以帮助。
PS: I left the timeout implementation as homework for you ;-)
PS:我把超时实现作为你的作业;-)
#2
3
I followed Anselm's advice in his post on the Ruby forum here.
我在这里的Ruby论坛上关注了Anselm的建议。
The function looks like this -
功能看起来像这样 -
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
This does the job, but I'd rather use a third-party gem that wraps this functionality. Anyone have any better ways of doing this? I have tried Terminator, it does exactly what I want but it does not seem to work on Windows.
这样做,但我宁愿使用包含此功能的第三方gem。有人有更好的方法吗?我尝试过终结者,它完全符合我的要求但它似乎不适用于Windows。
#1
12
You can use IO.pipe
and tell Process.spawn
to use the redirected output without the need of external gem.
您可以使用IO.pipe并告诉Process.spawn使用重定向输出而无需外部gem。
Of course, only starting with Ruby 1.9.2 (and I personally recommend 1.9.3)
当然,只从Ruby 1.9.2开始(我个人推荐1.9.3)
The following is a simple implementation used by Spinach BDD internally to capture both out and err outputs:
以下是Spinach BDD内部用于捕获out和err输出的简单实现:
# 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
The original source is in features/support/filesystem.rb
原始源位于features / support / filesystem.rb中
Is highly recommended you read Ruby's own Process.spawn documentation.
强烈建议您阅读Ruby自己的Process.spawn文档。
Hope this helps.
希望这可以帮助。
PS: I left the timeout implementation as homework for you ;-)
PS:我把超时实现作为你的作业;-)
#2
3
I followed Anselm's advice in his post on the Ruby forum here.
我在这里的Ruby论坛上关注了Anselm的建议。
The function looks like this -
功能看起来像这样 -
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
This does the job, but I'd rather use a third-party gem that wraps this functionality. Anyone have any better ways of doing this? I have tried Terminator, it does exactly what I want but it does not seem to work on Windows.
这样做,但我宁愿使用包含此功能的第三方gem。有人有更好的方法吗?我尝试过终结者,它完全符合我的要求但它似乎不适用于Windows。