33

重複の可能性:
サブプロセスの stdout/stderr をラップする

この質問で、hanan-nは、後で処理するために出力を文字列に保持しながら、stdout に出力する Python サブプロセスを持つことが可能かどうかを尋ねました。この場合の解決策は、すべての出力行をループして手動で出力することでした。

output = []
p = subprocess.Popen(["the", "command"], stdout=subprocess.PIPE)
for line in iter(p.stdout.readline, ''):
    print(line)
    output.append(line)

ただし、この解決策は、以下を満たしながら、stdout と stderr の両方に対してこれを実行したい場合には一般化されません。

  • stdout/stderr からの出力は、親プロセスの stdout/stderr にそれぞれ移動する必要があります。
  • 出力は可能な限りリアルタイムで行う必要があります (ただし、最後に文字列にアクセスする必要があるだけです)。
  • stdout 行と stderr 行の間の順序を変更するべきではありません (サブプロセスが stdout キャッシュと stderr キャッシュを異なる間隔でフラッシュする場合でも、それがどのように機能するかはよくわかりません。今のところ、full を含む適切なチャンクですべてを取得すると仮定しましょう。行?)

サブプロセスのドキュメントを調べましたが、これを達成できるものは見つかりませんでした。私が見つけた最も近い方法はstderr=subprocess.stdout、上記と同じソリューションを追加して使用することですが、通常の出力とエラーの区別が失われます。何か案は?解決策があるとすれば、 と への非同期読み取りが必要になると思いp.stdoutますp.stderr

これが私がやりたいことの例です:

p = subprocess.Popen(["the", "command"])
p.wait()  # while p runs, the command's stdout and stderr should behave as usual
p_stdout = p.stdout.read()  # unfortunately, this will return '' unless you use subprocess.PIPE
p_stderr = p.stderr.read()  # ditto
[do something with p_stdout and p_stderr]
4

3 に答える 3

37

この例は私にとってはうまくいくようです:

# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4

import subprocess
import sys
import select

p = subprocess.Popen(["find", "/proc"],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE)

stdout = []
stderr = []

while True:
    reads = [p.stdout.fileno(), p.stderr.fileno()]
    ret = select.select(reads, [], [])

    for fd in ret[0]:
        if fd == p.stdout.fileno():
            read = p.stdout.readline()
            sys.stdout.write('stdout: ' + read)
            stdout.append(read)
        if fd == p.stderr.fileno():
            read = p.stderr.readline()
            sys.stderr.write('stderr: ' + read)
            stderr.append(read)

    if p.poll() != None:
        break

print 'program ended'

print 'stdout:', "".join(stdout)
print 'stderr:', "".join(stderr)

一般に、複数のファイル ディスクリプタを同時に処理したいが、どのファイル ディスクリプタに読み込むデータがあるかわからない場合は、select またはそれに相当するもの (Twisted リアクタなど) を使用する必要があります。

于 2012-09-04T22:33:20.620 に答える
11

コンソールに出力し、サブプロセスの文字列 stdout/stderr をポータブルな方法でキャプチャするには:

from StringIO import StringIO

fout, ferr = StringIO(), StringIO()
exitcode = teed_call(["the", "command"], stdout=fout, stderr=ferr)
stdout = fout.getvalue()
stderr = ferr.getvalue()

Pythonサブプロセスteed_call()で定義されている場所は、ファイルと端末への子の出力を取得しますか?

.write()ファイルのようなオブジェクト (メソッド)を使用できます。

于 2012-09-05T18:25:10.807 に答える
2

上記のように2つのリーダーを作成します。1つはstdout1つで、stderrそれぞれを新しいスレッドで開始します。これは、プロセスによって出力されたのとほぼ同じ順序でリストに追加されます。必要に応じて、2つの別々のリストを維持します。

すなわち、

p = subprocess.Popen(["the", "command"])
t1 = thread.start_new_thread(func,stdout)  # create a function with the readers
t2 = thread.start_new_thread(func,stderr)
p.wait() 
# your logic here
于 2012-09-04T20:27:54.117 に答える