[英]subprocess.Popen handling stdout and stderr as they come
我正在嘗試從subprocess.Popen
調用處理stdout
和stderr
,它們通過subprocess.PIPE
捕獲它們,但是想要處理輸出(例如在終端上打印它們)。
我見過的所有當前解決方案都將等待完成Popen
調用,以確保捕獲所有stdout
和stderr
,以便可以對其進行處理。
這是一個帶有混合輸出的示例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
我知道有些系統調用可能會緩沖,我對此感到滿意,我要解決的一件事是尊重流的順序。
有沒有辦法能夠處理stdout
和stderr
因為它來自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
執行的cerr
和cout
。 結果是同一性的
我能夠通過使用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.