The order in which a process writes data to different pipes is lost after write.
There is no way you can tell if stdout has been written before stderr.
You can try to read data simultaneously from multiple file descriptors in a non-blocking way as soon as data is available, but this would only minimize the probability that the order is incorrect.
This program should demonstrate this:
#!/usr/bin/env python # -*- coding: utf-8 -*- import os import select import subprocess testapps={ 'slow': ''' import os import time os.write(1, 'aaa') time.sleep(0.01) os.write(2, 'bbb') time.sleep(0.01) os.write(1, 'ccc') ''', 'fast': ''' import os os.write(1, 'aaa') os.write(2, 'bbb') os.write(1, 'ccc') ''', 'fast2': ''' import os os.write(1, 'aaa') os.write(2, 'bbbbbbbbbbbbbbb') os.write(1, 'ccc') ''' } def readfds(fds, maxread): while True: fdsin, _, _ = select.select(fds,[],[]) for fd in fdsin: s = os.read(fd, maxread) if len(s) == 0: fds.remove(fd) continue yield fd, s if fds == []: break def readfromapp(app, rounds=10, maxread=1024): f=open('testapp.py', 'w') f.write(testapps[app]) f.close() results={} for i in range(0, rounds): p = subprocess.Popen(['python', 'testapp.py'], stdout=subprocess.PIPE , stderr=subprocess.PIPE) data='' for (fd, s) in readfds([p.stdout.fileno(), p.stderr.fileno()], maxread): data = data + s results[data] = results[data] + 1 if data in results else 1 print 'running %i rounds %s with maxread=%i' % (rounds, app, maxread) results = sorted(results.items(), key=lambda (k,v): k, reverse=False) for data, count in results: print '%03i x %s' % (count, data) print print "=> if output is produced slowly this should work as whished" print " and should return: aaabbbccc" readfromapp('slow', rounds=100, maxread=1024) print print "=> now mostly aaacccbbb is returnd, not as it should be" readfromapp('fast', rounds=100, maxread=1024) print print "=> you could try to read data one by one, and return" print " e.g. a whole line only when LF is read" print " (b's should be finished before c's)" readfromapp('fast', rounds=100, maxread=1) print print "=> but even this won't work ..." readfromapp('fast2', rounds=100, maxread=1)
and outputs something like this:
=> if output is produced slowly this should work as whished and should return: aaabbbccc running 100 rounds slow with maxread=1024 100 x aaabbbccc => now mostly aaacccbbb is returnd, not as it should be running 100 rounds fast with maxread=1024 006 x aaabbbccc 094 x aaacccbbb => you could try to read data one by one, and return e.g. a whole line only when LF is read (b's should be finished before c's) running 100 rounds fast with maxread=1 003 x aaabbbccc 003 x aababcbcc 094 x abababccc => but even this won't work ... running 100 rounds fast2 with maxread=1 003 x aaabbbbbbbbbbbbbbbccc 001 x aaacbcbcbbbbbbbbbbbbb 008 x aababcbcbcbbbbbbbbbbb 088 x abababcbcbcbbbbbbbbbb