title: How to capture output of a shell script running in a separate process, in a wxPython TextCtrl?
body: <p>A long running shell script produces stdout and stderr, which I would like to show on a textctrl in a GUI. This is possible using threading and separating the GUI thread from the shell script's thread. However when I implement multiprocessing, I hit a roadblock. Here's my -stripped down- code:</p>
  
  <pre><code>#!/usr/bin/env python
  
  import wx
  import sys, subprocess
  from multiprocessing import Process, Queue
  from Queue import Empty
  
  class MyFrame(wx.Frame):
      def __init__(self, *args, **kwds):
          wx.Frame.__init__(self, *args, **kwds)
  
          self.button = wx.Button(self, -1 , "Run")
          self.output = wx.TextCtrl(self, -1, '', style=wx.TE_MULTILINE|\
                                                        wx.TE_READONLY|wx.HSCROLL)
  
          self.Bind(wx.EVT_BUTTON, self.OnButton, self.button)
  
          sizer = wx.BoxSizer(wx.VERTICAL)
          sizer.Add(self.output, -1, wx.EXPAND, 0)
          sizer.Add(self.button)
          self.SetSizerAndFit(sizer)
          self.Centre()
  
      def OnButton(self, event):
          numtasks = 4 # total number of tasks to run
          numprocs = 2 # number of processors = number of parallel tasks
          work_queue = Queue()
          for i in xrange(numtasks):
               work_queue.put(i)
          processes = [Process(target=self.doWork, args=(work_queue, ))
                       for i in range(numprocs)]
          for p in processes:
              p.daemon = True
              p.start()
  
      def doWork(self, work_queue):
          while True:
              try:
                  x = work_queue.get(block=False)
                  self.runScript(x)
              except Empty:
                  print "Queue Empty"
                  break
  
      def runScript(self, taskno):
          print '## Now Running: ', taskno
          command = ['./script.sh']  
          proc = subprocess.Popen(command, shell=True, 
                                           stdout=subprocess.PIPE, 
                                           stderr=subprocess.STDOUT)
          while True:
              stdout = proc.stdout.readline()
              if not stdout:
                  break
              #sys.stdout.flush() #no need for flush, apparently it is embedded in the multiprocessing module
              self.output.AppendText(stdout.rstrip()) #this is the part that doesn't work.
  
  if __name__ == "__main__":
      app = wx.App(0)
      frame = MyFrame(None, title="shell2textctrl", size=(500,500))
      frame.Show(True)
      app.MainLoop()
  </code></pre>
  
  <p>I've tried many solutions upon others' suggestions. Among these are: using wx.CallAfter or wx.lib.delayedresult to make the GUI responsive; several threading recipes (eg. wxApplication Development Cookbook, threadpool, others...) and have the multiprocess() run from a separate thread; redefining sys.stdout.write to write to the textctrl; and whatnot. None of them were successfull. Can anyone please provide a solution together with working code? You can use this script written somewhere here by I forgot who:</p>
  
  <pre><code>#!/bin/tcsh -f
  @ i = 1
  while ($i &lt;= 20)
   echo $i
   @ i += 1
   sleep 0.2
  end
  </code></pre>