Search code examples
pythonsubprocessstdoutstderr

How to unify stdout and stderr, yet be able to distinguish between them?


I'd like to produce a readable HTML report of a process run. Towards that end, I'd like to track both stdout and stderr, and output them interleaved, yet distinguished - for example, the log will show them both combined according to the order they were emitted, but with stdout in black and stderr in bold red.

I can readily see a solution that will keep them distinguished: just redirect each to subprocess.PIPE. Of course, then they can't be recombined in order. It's also easy to unify them in order: just redirect stderr to subprocess.STDOUT. However, then they will be indistinguishable.

Thus getting the outputs to be either distinguished or combined in order is straightforward, but getting both is not.

What's the way to do that in Python?


Solution

  • You can use select() to multiplex the output. Suppose you have stdout and stderr being captured in pipes, this code will work:

    import select
    import sys
    
    inputs = set([pipe_stdout, pipe_stderr])
    
    while inputs:
      readable, _, _ = select.select(inputs, [], [])
      for x in readable:
        line = x.readline()
        if len(line) == 0:
          inputs.discard(x)
        if x == pipe_stdout
          print 'STDOUT', line
        if x == pipe_stderr
          print 'STDERR', line