Reputation: 13541
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.
Upvotes: 21
Views: 21221
Reputation: 81510
Do you need the output of popen
? If not, do you want to use Kernel#system
or some other command?
Upvotes: 1
Reputation: 651
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)
Upvotes: 3
Reputation: 13541
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.
Upvotes: 6
Reputation: 5107
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
.
Upvotes: 6
Reputation: 66751
Apparently the canonical way to do this is:
Process.wait(popened_io.pid)
Upvotes: 23
Reputation: 2179
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.
Upvotes: 22