web-dev-qa-db-ja.com

subprocess.Popen()から出力を取得する方法。 proc.stdout.readline()ブロック、データ出力なし

Test_Pipe.pyの実行からの出力が必要です。Linuxで次のコードを試しましたが、うまくいきませんでした。

Test_Pipe.py

_import time
while True :
    print "Someting ..."
    time.sleep(.1)
_

Caller.py

_import subprocess as subp
import time

proc = subp.Popen(["python", "Test_Pipe.py"], stdout=subp.PIPE, stdin=subp.PIPE)

while True :
    data = proc.stdout.readline() #block / wait
    print data
    time.sleep(.1)
_

proc.stdout.readline()はブロックされたため、データは出力されません。

38
wearetherock

もちろんsubprocess.communicateを使用できますが、リアルタイムの入出力を探していると思います。

プロセスはおそらく入力を待機しているため、readlineはブロックされました。これを次のように文字ごとに読み取ることができます。

import subprocess
import sys

process = subprocess.Popen(
    cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

while True:
    out = process.stdout.read(1)
    if out == '' and process.poll() != None:
        break
    if out != '':
        sys.stdout.write(out)
        sys.stdout.flush()
44
Nadia Alramli

Nadiaのスニペットは機能しますが、1バイトのバッファーでreadを呼び出すことは非常にお勧めできません。これを行うより良い方法は、fcntlを使用してstdoutファイル記述子を非ブロックに設定することです。

fcntl.fcntl(
    proc.stdout.fileno(),
    fcntl.F_SETFL,
    fcntl.fcntl(proc.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
)

次に、selectを使用して、データの準備ができているかどうかをテストします

while proc.poll() == None:
    readx = select.select([proc.stdout.fileno()], [], [])[0]
    if readx:
        chunk = proc.stdout.read()
        print chunk

彼女は、Caller.pyおよびTest_Pipe.pyが提供されたとおりに動作するために投稿したものとあなたの問題が異なる必要があるという点で正しかった。

21
Derrick Petzold

Test_Pipe.pyはデフォルトで標準出力をバッファするため、Caller.pyprocは、子のバッファがいっぱいになるまで出力を表示しません(バッファサイズが8KBの場合、約1分かかります) Test_Pipe.pyの標準出力バッファー)。

出力をバッファなし(テキストストリーム用にラインバッファ)にするには、 -u flag を子Pythonスクリプトに渡します。サブプロセスを読み取ることができます。 「リアルタイム」の行ごとの出力:

import sys
from subprocess import Popen, PIPE

proc = Popen([sys.executable, "-u", "Test_Pipe.py"], stdout=PIPE, bufsize=1)
for line in iter(proc.stdout.readline, b''):
    print line,
proc.communicate()

Python以外の子プロセスのブロックバッファリングの問題を解決する方法については、 Python:subprocess.communicate()からストリーミング入力を読み取る のリンクを参照してください。

14
jfs

「サブプロセスの出力をメインプロセスにリアルタイムで取得する」などのタスクのバッファリングで常に発生する可能性のある多くの問題を回避するために、すべての非Windowsプラットフォームで pexpect を使用することを常にお勧めします- wexpect Windowsでは、subprocessの代わりに、そのようなタスクが必要な場合。

13
Alex Martelli