簡體   English   中英

subprocess.Popen處理stdout和stderr

[英]subprocess.Popen handling stdout and stderr as they come

我正在嘗試從subprocess.Popen調用處理stdoutstderr ,它們通過subprocess.PIPE捕獲它們,但是想要處理輸出(例如在終端上打印它們)。

我見過的所有當前解決方案都將等待完成Popen調用,以確保捕獲所有stdoutstderr ,以便可以對其進行處理。

這是一個帶有混合輸出的示例Python腳本,我無法在實時處理它時(或盡可能實時)復制訂單:

$ cat mix_out.py

import sys

sys.stdout.write('this is an stdout line\n')
sys.stdout.write('this is an stdout line\n')
sys.stderr.write('this is an stderr line\n')
sys.stderr.write('this is an stderr line\n')
sys.stderr.write('this is an stderr line\n')
sys.stdout.write('this is an stdout line\n')
sys.stderr.write('this is an stderr line\n')
sys.stdout.write('this is an stdout line\n')

似乎可能有效的一種方法是使用線程,因為那時讀取將是異步的,並且可以在subprocess進程產生輸出時進行處理。

當前執行stdout的當前實現首先是stderr最后是stderr ,如果輸出最初在兩者之間交替,則可能是騙人的:

cmd = ['python', 'mix_out.py']

process = subprocess.Popen(
    cmd,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    close_fds=True,
    **kw
)

if process.stdout:
    while True:
        out = process.stdout.readline()
        if out == '' and process.poll() is not None:
            break
        if out != '':
            print 'stdout: %s' % out
            sys.stdout.flush()

if process.stderr:
    while True:
        err = process.stderr.readline()
        if err == '' and process.poll() is not None:
            break
        if err != '':
            print 'stderr: %s' % err
            sys.stderr.flush()

如果我運行以上(保存為out.py )來處理上面的mix_out.py示例腳本, mix_out.py順序處理流(按預期方式):

$ python out.py
stdout: this is an stdout line
stdout: this is an stdout line
stdout: this is an stdout line
stdout: this is an stdout line
stderr: this is an stderr line
stderr: this is an stderr line
stderr: this is an stderr line
stderr: this is an stderr line

我知道有些系統調用可能會緩沖,我對此感到滿意,我要解決的一件事是尊重流的順序。

有沒有辦法能夠處理stdoutstderr因為它來自subprocess進程不必使用線程? (代碼在無法進行線程化的受限遠程系統中執行)。

需要區分stdout和stderr是必須的(如示例輸出中所示)

理想情況下,沒有額外的庫是最好的(例如,我知道pexpect解決了這個問題)

很多例子都提到了select的使用,但是我沒有想出能夠保持輸出順序的東西。

很抱歉,如果我誤解了這個問題...但是如果你正在尋找一種方法讓 subprocess.Popen 實時輸出到stdout / stderr ,你應該能夠實現:

import sys, subprocess
p = subprocess.Popen(cmdline,
                     stdout=sys.stdout,
                     stderr=sys.stderr)

也許, stderr=subprocess.STDOUT ,可以簡化您的過濾?

如果這不是您正在尋找的,抱歉。 但希望它能滿足其他人的需求。

我在這里找到了工作示例 (請參閱capture_together.py列表)。 編譯的C ++代碼混合了在Windows和UNIX操作系統上作為子cout執行的cerrcout 結果是同一性的

我能夠通過使用select.select()解決這個問題

process = subprocess.Popen(
    cmd,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    close_fds=True,
    **kw
)

while True:
    reads, _, _ = select(
        [process.stdout.fileno(), process.stderr.fileno()],
        [], []
    )

    for descriptor in reads:
        if descriptor == process.stdout.fileno():
            read = process.stdout.readline()
            if read:
                print 'stdout: %s' % read

        if descriptor == process.stderr.fileno():
            read = process.stderr.readline()
            if read:
                print 'stderr: %s' % read
        sys.stdout.flush()

    if process.poll() is not None:
        break

通過將文件描述符傳遞給reads參數上的select()select()第一個參數)並循環它們(只要process.poll()指示進程仍處於活動狀態)。

不需要線程。 代碼改編自此stackoverflow答案

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM