PythonPopenInterleavedStderrStdout

18th April 2017 at 9:00am
TechnicalNotes

Taken from http://stackoverflow.com/a/31867499 with some modifications.

import logging
from subprocess import Popen, PIPE
from threading import Thread
from Queue import Queue

def reader(pipe, queue):
    try:
        with pipe:
            for line in iter(pipe.readline, b''):
                queue.put((pipe, line))
    finally:
        # Descriptor was closed. Signal this to the consumer of
        # the queue
        queue.put(None)

command = [
    '/bin/bash',
    '-c',
    'echo "stdout 1"; sleep 1; >&2 echo "stderr 1"; sleep 1; echo "stdout 2"; sleep 1; >&2 echo "stderr 2"',
    ]

process = Popen(command, stdout=PIPE, stderr=PIPE, bufsize=1)
q = Queue()

Thread(target=reader, args=[process.stdout, q]).start()
Thread(target=reader, args=[process.stderr, q]).start()

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Since we have two descriptors - we are expecting two
# signals (None value) on the queue
for _ in range(2):
    for source, line in iter(q.get, None):
        if source == process.stdout:
            logger.info(line.rstrip())
        elif source == process.stderr:
            logger.error(line.rstrip())