From: Robert Klemme Date: 2009-12-16T17:05:54+09:00 Subject: Re: working with a slow pipe (IO.popen) 2009/12/16 bwv549 : > On Dec 15, 11:32 pm, Eric Wong wrote: >> bwv549 wrote: >> > I'm doing some work with pymol and having trouble getting all the >> > pymol output out: >> >> > # I open it in quiet/commandline mode with a pipe: >> > IO.popen("pymol -cq -p", 'w+') do |pipe| >> >   pipe.puts "load file.pdb, mymodel\n" >> >   pipe.puts "run my_script.py" >> >   # this command will generate a whole bunch of output to stdout >> >   pipe.puts "my_script mymodel" >> >   sleep(5)  # <--- this is what I have to do in order to get the >> > output >> >   pipe.close_write >> >   output = pipe.read >> > end >> >> > What is annoying is that unless I sleep for 2-5 seconds I don't get >> > output or (even worse) my output is cut off.  There has to be a way >> > besides arbitrarily sleeping to ensure that the command is finished. >> > I've tried things like piping in "quit", but that doesn't seem to >> > work.  Anybody know how to solve this?  I'm happy to use a different >> > approach if it means I can be sure I get all of my output out.   -- >> > Thanks! >> >> Hi, >> >> I don't know about pymol, but some apps do not respond well to having >> its stdin closed on it with close_write.  pipe.read should just block >> until you get output, otherwise put an IO.select([pipe) in front of it. >> >> Does this work? >> >>   IO.popen("pymol -cq -p", 'w+') do |pipe| >>     pipe.puts "load file.pdb, mymodel\n" >>     pipe.puts "run my_script.py" >>     pipe.puts "my_script mymodel" >> >>     # IO.select([pipe]) # you shouldn't need to uncomment this... >> >>     output = pipe.read >>   end >> >> -- >> Eric Wong > > both of those hang indefinitely.  It doesn't hang if I add the line: > >   pipe.puts "quit" > > but that doesn't give me all the output either.  So maybe pymol > behaves differently than many commandline programs? What does the documentation of "pymol" say? > Here is what I've worked out for the time being.  It opens a thread > for reading the output and asks if there is any output every 1/2 > second.  Once we go 1/2 second without output we kill the thread. > > my_string = "" > Open3.popen3("pymol -cq -p") do |si, so, se| >  si.puts "load file.pdb, mymodel\n" >  si.puts "run my_script.py\n" >  si.puts "myscript mymodel\n" > >  forstdout = Thread.new do >    Thread.current['lines'] = [] >    while line = so.gets >      Thread.current['lines'] << line >    end >  end You don't need the thread local for this to work. Note there is also Thread#value! How does this work: output = IO.popen("pymol -cq -p", 'w+') do |pipe| reader = Thread.new { pipe.to_a } pipe.puts "load file.pdb, mymodel" pipe.puts "run my_script.py" # this command will generate a whole bunch of output to stdout pipe.puts "my_script mymodel" pipe.close_write reader.value end Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/