【问题标题】:Popen mixed data stream?弹出混合数据流?
【发布时间】:2013-05-06 10:34:33
【问题描述】:

我在 Windows 上遇到了 Popen 和 Pipes 的问题。我认为 Popen 在 stdout 和 stderr 之间混合了数据。 当我的程序只读取标准输出时,一切正常,但是当我读取标准输出和标准错误时,标准输出中的一些数据被抛出到标准错误。 我的阅读方法:

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

self._read_obj 是标准错误或标准输出。 你知道我该如何解决这个问题吗?

【问题讨论】:

    标签: python pipe popen


    【解决方案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()
    

    由于您没有发布任何相关代码,所以它应该是这样的。 请注意,即使没有可获取的内容,readline 仍会为您提供输出,因为 stderr 有时会“挂起”等待输出,但如果您使用的是子进程,这是要走的路。

    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)
    

    类似的东西应该可以。 如果您不需要分离两个输出,而只想读取数据并将其放入队列中,您可以这样做:

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

    这是我通常做的事情

    (我并不是说这是最佳实践,但它确实有效)

    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)
    

    【讨论】:

    • 对不起。是的,我正在使用子进程,但我不能总是“等待”readline,所以我的方式对我来说更好。
    • @Tomek 无论如何,我已经向您展示了如何分离两个输出(这是您最初的问题)。这是一种处理 stderr 的方法,这样它就不会阻塞您的代码,同时仍然能够读取 stdout,您也可以将 stdout 以类似的方式放置,但出于说明目的,我将其保留为这种方式。
    • 我不知道如何......但它的工作原理 - 我的方式是相似的,我试过:Popen('long cmd string', shell = True, stdout...) 谢谢你的时间:)
    • 前两个代码示例可能会导致死锁(操作系统缓冲区可能会填满并阻塞子进程)。最后一个示例以非线程安全的方式使用列表(可能会丢失数据)。
    【解决方案2】:

    为 stdout/stderr 分离输出的简单方法是使用 .communicate():

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

    它读取内存中的所有输出。

    如果要在子进程运行时处理输出;你需要 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-21
      • 1970-01-01
      • 2021-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多