我正在使用Python的subprocess.communicate()
從運行大約一分鐘的進程讀取stdout。Python:讀取來自subprocess.communicate()的流輸入
如何以流方式打印出該進程的stdout的每一行,以便我可以在輸出生成時看到輸出,但在繼續之前仍會阻止進程終止?
subprocess.communicate()
似乎一次給所有的輸出。
我正在使用Python的subprocess.communicate()
從運行大約一分鐘的進程讀取stdout。Python:讀取來自subprocess.communicate()的流輸入
如何以流方式打印出該進程的stdout的每一行,以便我可以在輸出生成時看到輸出,但在繼續之前仍會阻止進程終止?
subprocess.communicate()
似乎一次給所有的輸出。
請注意,我認爲J.F. Sebastian's method (below)更好。
下面是一個簡單的例子(沒有進行錯誤檢查):
import subprocess
proc = subprocess.Popen('ls',
shell=True,
stdout=subprocess.PIPE,
)
while proc.poll() is None:
output = proc.stdout.readline()
print output,
如果ls
結束得太快,那麼您已經閱讀所有的數據之前,while循環可能會結束。
您可以趕上在標準輸出餘這樣說:
output = proc.communicate()[0]
print output,
該方案是否成爲python doc引用的緩衝區阻塞問題的受害者? – 2010-04-26 19:22:08
@海因裏希,緩衝區阻塞問題不是我理解得很好。我相信(僅僅從google搜索),只有當你沒有從while循環中讀取stdout(和stderr?)時纔會出現這個問題。所以我認爲上面的代碼是可以的,但我不能肯定地說。 – unutbu 2010-04-26 19:44:44
這實際上也從一個阻塞問題的困擾,幾年前我沒有結束麻煩,其中的readline將阻止,直到它得到了即使PROC結束了一個換行符。我不記得了解決方案,但我認爲它有事情做與做讀取一個工作線程,只是循環'而proc.poll()是無:time.sleep(0)'或諸如此類的話。基本上,您需要確保輸出換行符是流程所做的最後一件事(因爲您不能讓解釋器時間再次循環),或者您需要做一些「花哨」的事情。 – 2010-04-26 20:05:32
如果你想要一個非阻塞的方法,不要使用process.communicate()
。如果將subprocess.Popen()
參數stdout
設置爲PIPE
,則可以從process.stdout
中讀取並檢查過程是否仍使用process.poll()
運行。
[非阻塞方法不是直接的(http://stackoverflow.com/q/375427/4279) – jfs 2015-09-23 14:45:34
我相信從以流方式的過程收集輸出最簡單的方法是這樣的:
import sys
from subprocess import *
proc = Popen('ls', shell=True, stdout=PIPE)
while True:
data = proc.stdout.readline() # Alternatively proc.stdout.read(1024)
if len(data) == 0:
break
sys.stdout.write(data) # sys.stdout.buffer.write(data) on Python 3.x
的readline()
或read()
函數應該只在EOF結束後返回一個空字符串,否則它將在沒有任何內容需要讀取時阻塞(readline()
包含換行符,所以在空行上,它返回「\ n」)。這避免了在循環之後需要一個尷尬的最終communicate()
調用。
對於具有很長行read()
的文件,可能更適合減少最大內存使用量 - 傳遞給它的數量是任意的,但排除它會導致一次讀取整個管道輸出,這可能不合需要。
'data = proc.stdout.read()'阻塞,直到讀取所有*數據。你可能會把它與os.read(fd,maxsize)混淆起來,它可以提前返回(只要有數據可用)。 – jfs 2013-08-22 09:15:24
你是對的,我錯了。但是,如果將合理數量的字節作爲參數傳遞給'read()',那麼它可以正常工作,並且只要最大行長度合理,'readline()'也可以正常工作。相應地更新我的答案。 – 2013-08-22 23:46:34
儘快子進程刷新其標準輸出緩衝區獲得由線子輸出線:
#!/usr/bin/env python2
from subprocess import Popen, PIPE
p = Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1)
with p.stdout:
for line in iter(p.stdout.readline, b''):
print line,
p.wait() # wait for the subprocess to exit
iter()
來,儘快爲他們寫要解決the read-ahead bug in Python 2讀線。
如果子進程的stdout在非交互模式下使用塊緩衝而不是行緩衝(導致輸出延遲,直到孩子的緩衝區已滿或被孩子明確刷新),那麼您可以嘗試強制使用pexpect
, pty
modules或unbuffer
, stdbuf
, script
utilities無緩衝輸出,見Q: Why not just use a pipe (popen())?
這裏的Python 3中的代碼:
#!/usr/bin/env python3
from subprocess import Popen, PIPE
with Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1, universal_newlines=True) as p:
for line in p.stdout:
print(line, end='')
注意:與輸出子過程的Python 2字節串原樣; Python 3使用文本模式(cmd的輸出使用locale.getpreferredencoding(False)
編碼進行解碼)。
如果你只是想通過實時傳遞輸出,很難得到比這更簡單:
import subprocess
# This will raise a CalledProcessError if the program return a nonzero code.
# You can use call() instead if you don't care about that case.
subprocess.check_call(['ls', '-l'])
見docs for subprocess.check_call()。
如果你需要處理它的輸出,當然,循環。但如果你不這樣做,那就保持簡單。
編輯:J.F. Sebastian指出二者,對於輸出和錯誤參數的缺省值通過sys.stdout來和sys.stderr,那如果sys.stdout的和sys.stderr已被替換,這將失敗(比如,用於在測試中捕獲輸出)。
如果將'sys.stdout'或'sys.stderr'替換爲沒有真正的fileno()的文件類對象,它將不起作用。如果'sys.stdout','sys.stderr'沒有被替換,那麼它更簡單:'subprocess.check_call(args)'。 – jfs 2015-09-22 18:47:24
謝謝!我意識到替換sys.stdout/stderr的變幻莫測,但不知何故,如果你忽略參數,它會將stdout和stderr傳遞給正確的地方。除非我想要'CalledProcessError',否則我喜歡'call()'通過'check_call()'。 – Nate 2015-09-23 14:41:29
'python -mthis':*「錯誤不應該默默通過。」 除非明確聲明爲無效。「*這就是爲什麼_example code_應該比'call()'更適合'check_call()'的原因。 – jfs 2015-09-23 14:42:43
myCommand="ls -l"
cmd=myCommand.split()
# "universal newline support" This will cause to interpret \n, \r\n and \r equally, each as a newline.
p = subprocess.Popen(cmd, stderr=subprocess.PIPE, universal_newlines=True)
while True:
print(p.stderr.readline().rstrip('\r\n'))
解釋你的解決方案只是爲了讓人們更好地理解,總是很好 – DaFois 2017-11-12 23:44:50
相關:[獲取實時輸出使用子過程](http://stackoverflow.com/q/803265/4279) – jfs 2014-10-16 20:11:54