Popen mixed data stream?

。_饼干妹妹 提交于 2020-01-16 19:37:06

问题


I've got problem with Popen and Pipes on Windows. I think Popen mixed data between stdout and stderr. When my program reads only stdout everything is OK but when I read stdout and stderr some data from stdout is thrown to stderr. My read method:

    for line in iter(self._read_obj.readline, b''):
        self._queue.put(line)
        sleep(.2)

Where self._read_obj is either stderr or stdout. Do you know how can I solve this?


回答1:


from subproccess import *
x = Popen('sh /root/script.sh', stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=True)
print x.stdout.readline()
print x.stderr.readline()

Since you don't posted any relevant code, here's how it should look. Note that readline will still give you output even tho there is none to fetch, as to stderr sometimes "hangs" waiting for output, but this is the way to go if you're using subprocess.

from subprocess import PIPE, Popen
x = Popen(['ls', '-l'], stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=False)
while 1:
    if x.poll() != None:
        break
    _queue.put(x.stdout.readline())
    sleep(0.2)

Something like that should work. If you don't need to separate the two outputs, and you just want to read the data and att it to a queue, you can do:

x = Popen(['ls', '-l'], stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=False)

Here's what i normally do

(and i'm not saying this is the best practice of things, but it works)

from threading import Thread, enumerate
from subprocess import Popen, PIPE
from time import sleep

class nonBlockingStderr(Thread):
    def __init__(self, handle):
        self.handle = handle
        self.stderrOutput = []
        Thread.__init__(self)
        self.start()
    def stderr(self):
        if len(self.stderrOutput) <= 0:
            return ''
        else:
            ret = self.stderrOutput[0]
            self.stderrOutput = self.stderrOutput[1:]
            return ret
    def run(self):
        while 1:
            line = self.handle.readline()
            if len(line) > 0:
                self.stderrOutput.append(line)
            sleep(0.1)

from subprocess import PIPE, Popen
x = Popen(['ls', '-l'], stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=False)
errHandle = nonBlockingStderr(x.stderr)
while 1:
    if x.poll() != None:
        break
    _queue.put(errHandle.stderr())
    _queue.put(x.stdout.readline())
    sleep(0.2)



回答2:


A simple way to separate output for stdout/stderr is to use .communicate():

from subprocess import Popen, PIPE

p = Popen(command, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()

It reads all output in memory.

If you want to process the output while the subprocess is running; you need threads on Windows:

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

def reader_thread(pipe, process_line):
    for line in iter(pipe.readline, b''):
        process_line(line)
    pipe.close()

def start_reader_thread(pipe, process_line):
    t = Thread(target=reader_thread, args=[pipe, process_line])
    t.daemon = True
    t.start()

q = Queue()
p = Popen(command, stdout=PIPE, stderr=PIPE, bufsize=1)
start_reader_thread(p.stdout, lambda line: q.put(('stdout', line)))
start_reader_thread(p.stderr, lambda line: q.put(('stderr', line)))

while p.poll() is None: # while subprocess is running
    try:
        source, line = q.get_nowait()
    except Empty:
        pass
    else:
        # use source, line here
        print(source, line)
q.put(None)
for source, line in iter(q.get, None): # process the rest
    # use source, line here
    print("after", source, line)


来源:https://stackoverflow.com/questions/16396873/popen-mixed-data-stream

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!