How to wait for process to finish using IO.popen?

2020-02-23 06:20发布

I'm using IO.popen in Ruby to run a series of command line commands in a loop. I then need to run another command outside of the loop. The command outside of the loop cannot run until all of the commands in the loop have terminated.

How do I make the program wait for this to happen? At the moment the final command is running too soon.

An example:

for foo in bar
    IO.popen(cmd_foo)
end
IO.popen(another_cmd)

So all cmd_foos need to return before another_cmd is run.

6条回答
Rolldiameter
2楼-- · 2020-02-23 06:58

Do you need the output of popen? If not, do you want to use Kernel#system or some other command?

查看更多
Juvenile、少年°
3楼-- · 2020-02-23 07:07

I think you'd need to assign the results from the IO.popen calls within the cycle to the variables, and keep calling read() on them until eof() becomes true on all.

Then you know that all the programs have finished their execution and you can start another_cmd.

查看更多
手持菜刀,她持情操
4楼-- · 2020-02-23 07:11
for foo in bar
  out = IO.popen(cmd_foo)
  out.readlines
end
IO.popen(another_cmd)

Reading the output to a variable then calling out.readlines did it. I think that out.readlines must wait for the process to end before it returns.

Credit to Andrew Y for pointing me in the right direction.

查看更多
可以哭但决不认输i
5楼-- · 2020-02-23 07:15

Apparently the canonical way to do this is:

 Process.wait(popened_io.pid)
查看更多
萌系小妹纸
6楼-- · 2020-02-23 07:16

Use the block form and read all the content:

IO.popen "cmd" do |io|
  # 1 array
  io.readlines

  # alternative, 1 big String
  io.read

  # or, if you have to do something with the output
  io.each do |line|
    puts line
  end

  # if you just want to ignore the output, I'd do
  io.each {||}
end

If you do not read the output, it may be that the process blocks because the pipe connecting the other process and your process is full and nobody reads from it.

查看更多
对你真心纯属浪费
7楼-- · 2020-02-23 07:16

I suggest you use Thread.join to synchronize the last popen call:

t = Thread.new do
    for foo in bar
       IO.popen(cmd_foo)
    end
end

t.join

IO.popen(another_cmd)
查看更多
登录 后发表回答