1. ホーム
  2. パイソン

[解決済み】サブプロセスコマンドからのライブ出力

2022-04-04 04:20:06

質問

ハイドロダイナミクスコードのドライバとして、パイソンスクリプトを使用しています。 シミュレーションを実行するとき、私は subprocess.Popen の出力を収集し、コードを実行します。 stdoutstderrsubprocess.PIPE --- そして、出力情報を印刷(およびログファイルへの保存)し、エラーをチェックすることができるのです。 問題は、コードがどのように進行しているのかが全く分からないことです。コマンドラインから直接実行すると、どのイテレーションで、何時、次のタイムステップが何であるか、などの出力が得られます。

出力を保存し(ロギングとエラーチェックのため)、またライブストリーミング出力を生成する方法はありますか?

私のコードの該当部分です。

ret_val = subprocess.Popen( run_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True )
output, errors = ret_val.communicate()
log_file.write(output)
print output
if( ret_val.returncode ):
    print "RUN failed\n\n%s\n\n" % (errors)
    success = False

if( errors ): log_file.write("\n\n%s\n\n" % errors)

元々、私は run_command を通して tee そのため、コピーが直接ログファイルに送られ、ストリームはまだ直接ターミナルに出力されています -- しかしこの方法では、(私の知る限り)エラーを保存できません。


これまでの私の一時的な解決策。

ret_val = subprocess.Popen( run_command, stdout=log_file, stderr=subprocess.PIPE, shell=True )
while not ret_val.poll():
    log_file.flush()

を実行し、別の端末で tail -f log.txt (s.t. log_file = 'log.txt' ).

解決方法は?

Python 3 の TLDR です。

import subprocess
import sys
with open('test.log', 'wb') as f: 
    process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
    for c in iter(lambda: process.stdout.read(1), b''): 
        sys.stdout.buffer.write(c)
        f.buffer.write(c)


これを行うには、2つの方法があります。 read または readline 関数と行う。

import subprocess
import sys
with open('test.log', 'w') as f:  # replace 'w' with 'wb' for Python 3
    process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
    for c in iter(lambda: process.stdout.read(1), ''):  # replace '' with b'' for Python 3
        sys.stdout.write(c)
        f.write(c)

または

import subprocess
import sys
with open('test.log', 'w') as f:  # replace 'w' with 'wb' for Python 3
    process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
    for line in iter(process.stdout.readline, ''):  # replace '' with b'' for Python 3
        sys.stdout.write(line)
        f.write(line)

または readerwriter ファイルを作成します。を渡す。 writerPopen から読み込みます。 reader

import io
import time
import subprocess
import sys

filename = 'test.log'
with io.open(filename, 'wb') as writer, io.open(filename, 'rb', 1) as reader:
    process = subprocess.Popen(command, stdout=writer)
    while process.poll() is None:
        sys.stdout.write(reader.read())
        time.sleep(0.5)
    # Read the remaining
    sys.stdout.write(reader.read())

このようにすると、データを書き込むのは test.log と標準出力に出力されます。

ファイルアプローチの唯一の利点は、あなたのコードがブロックされないことです。つまり、その間にやりたいことを何でもやって、好きなときに reader をノンブロッキングで実行します。このような場合 PIPE , readreadline は、それぞれ1文字がパイプに書き込まれるか、1行がパイプに書き込まれるまでブロックされます。