0

There seem to be a lot of ways to invoke some system process via the command line using python, and then to read the output once the process is complete. For example, the subprocess module can accomplish this via subprocess.Popen(['ls']).

Is there a way to read the output from a command while it is still running?

For example, if I invoke the python script multiply.py:

import time

def multiply(a,b):
    newA = a
    newB = b
    while True: #endless loop
        newA = newA+1
        newB = newB+1

        product = newA * newB
        print 'Product: ',product
        time.sleep(1)


multiply(40,2)

using something along the lines of subprocess.Popen(['python', 'multiply.py]), is there a way to

  1. Start the process
  2. Silently/actively capture all the output while the process is running
  3. 'jump in' at any time to check the contents of the entire output?

The above python script is a model of the sort of process from which I'm interested in capturing output, i.e. there is an endless loop, which prints an output every second; it is this output that I'm interested in actively monitoring/capturing.

Ryan
  • 3,041
  • 1
  • 18
  • 31
  • Tried those suggestions: they didn't solve the problem – Ryan Dec 20 '14 at 12:59
  • *"they didn't solve the problem"* is not very informative. Please, [edit] your question and specify exactly how your case is different: what happens when you run the solution from the duplicate question? What do you expect to happen instead? Mention how do you run the script (OS, Python version, IDE or terminal app). I assume that you can make small modifications such as `entire_output.append(line)` yourself. – jfs Dec 22 '14 at 05:51

1 Answers1

0

Here is an implementation that opens the process on another thread (so you won't have to block the main thread) and communicates back lines using a Queue. The thread is killed on demand using an Event:

#!/usr/bin/env python

from subprocess import Popen, PIPE
from threading import Thread, Event
from Queue import Queue
from time import sleep

# communicates output lines from process to main thread
lines = Queue()
# kills thread
kill = Event()


def runner():
    p = Popen(["python", "multiply.py"], stdout=PIPE)
    # to get stream behaviour
    while p.poll() is None and not kill.isSet():
        lines.put(p.stdout.readline())

    p.kill()
    # in your use case this is redundant unless the process
    # is terminated externally - because your process is never done
    # after process finished some lines may have been missed
    if not kill.isSet():
        for line in p.stdout.readlines():
            lines.put(line)

# open process on another thread    
t = Thread(target=runner)
t.start()

# do stuff - lines aggregated on the queue    
print "First run"
sleep(1)
while not lines.empty():
    print lines.get()

# move to more important stuff...
sleep(3)

# now check the output we missed
print "Second run"
while not lines.empty():
    print lines.get()

# done doing stuff

# tell thread to kill itself
kill.set()
# wait for thread
t.join()
print "done"
Reut Sharabani
  • 27,609
  • 5
  • 62
  • 82
  • Thanks for your reply. How would I use this to check the command line output at a particular time? The code ran for ~4min without outputting any command line output. – Ryan Dec 20 '14 at 14:29
  • @Ryan you can consume the queue at any time you see fit. if you want the output at a particular time you can attach a read timestamp to each element and create tuples in the queue like `lines.put((time.time(), p.stdout.readline(),))`. Make sure you import `time` from `time`. If you expect something else please update you question to be more specific. – Reut Sharabani Dec 20 '14 at 14:53