On Dec 15, 11:32    򮮮
> bwv549 <jtpri... / gmail.com> 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.     > > 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.      §  > > 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.     > 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?

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

  past_size = -1
  loop do
    sleep(0.5)
    current_size = forstdout['lines'].size
    break if current_size == past_size
    past_size = current_size
  end
  my_string = forstdout['lines']
  forstdout.kill
end

This is not the fastest method, but it does seem to work OK.  I would
still love to hear other ideas.