経由で開始された実行中の長いプロセスからstdoutをキャプチャしたいので、引数としてsubprocess.Popen(...)
使用しています。stdout=PIPE
ただし、これは長時間実行されるプロセスであるため、出力をコンソールに送信して (パイプ処理していないかのように)、スクリプトがまだ機能していることをスクリプトのユーザーに知らせたいと考えています。
これはまったく可能ですか?
乾杯。
長時間実行されるサブプロセスが実行しているバッファリングにより、コンソールの出力がぎくしゃくし、UX が非常に悪くなります。代わりにpexpect (または、Windows ではwexpect ) を使用して、このようなバッファリングを無効にし、サブプロセスからスムーズで通常の出力を取得することを検討することをお勧めします。例 (ほぼすべての unix-y システムで、pexpect をインストールした後):
>>> import pexpect
>>> child = pexpect.spawn('/bin/bash -c "echo ba; sleep 1; echo bu"', logfile=sys.stdout); x=child.expect(pexpect.EOF); child.close()
ba
bu
>>> child.before
'ba\r\nbu\r\n'
バとブはタイミングよく(約1秒間隔)入ってきます。出力は通常の端末処理の対象ではないため、キャリッジ リターンはそこに残されていることに注意してください.replace
。\n
サブプロセスがバイナリ データを stdout に書き込んでいる場合に備えて、処理を行わないことが重要です -- これにより、すべてのデータがそのまま残ることが保証されます!-)。
S. Lott のコメントは、 Getting realtime output using subprocessとPython の別のプロセスからの stdout のリアルタイム インターセプトを指しています。
ここでのアレックスの回答が彼の回答 1085071 とは異なることに興味があります。参照されている他の 2 つの質問の回答を使った私の簡単な小さな実験では、良い結果が得られました...
上記のアレックスの回答に従って wexpect を見に行きましたが、コードのコメントを読んで、それを使用することについてあまり良い気持ちが残っていなかったと言わざるを得ません。
ここでのメタ質問は、いつ pexpect/wexpect が付属のバッテリーの 1 つになるかということだと思います。
または、プロセスをティーにパイプして、ストリームの 1 つだけをキャプチャすることもできます。の線に沿った何かsh -c 'process interesting stuff' | tee /dev/stderr
。
もちろん、これは Unix ライクなシステムでのみ機能します。
print
パイプから読み取るように単純化できますか?
上記の pty.openpty() の提案に触発され、python2.6、linux でテストされました。バッファリングなしで、これを適切に機能させるのに時間がかかったので、公開しています...
def call_and_peek_output(cmd, shell=False):
import pty, subprocess
master, slave = pty.openpty()
p = subprocess.Popen(cmd, shell=shell, stdin=None, stdout=slave, close_fds=True)
os.close(slave)
line = ""
while True:
try:
ch = os.read(master, 1)
except OSError:
# We get this exception when the spawn process closes all references to the
# pty descriptor which we passed him to use for stdout
# (typically when it and its childs exit)
break
line += ch
sys.stdout.write(ch)
if ch == '\n':
yield line
line = ""
if line:
yield line
ret = p.wait()
if ret:
raise subprocess.CalledProcessError(ret, cmd)
for l in call_and_peek_output("ls /", shell=True):
pass