web-dev-qa-db-ja.com

Python:subprocess.call、stdout to file、stderr to file、stderrを画面にリアルタイムで表示

Pythonでラッパーを作成しているコマンドラインツール(実際にはいくつか)があります。

このツールは通常、次のように使用されます。

 $ path_to_tool -option1 -option2 > file_out

ユーザーは、file_outに書き込まれた出力を取得し、実行中のツールのさまざまなステータスメッセージを表示することもできます。

Stderr(ステータスメッセージ)をファイルに記録しながら、この動作を再現したいと思います。

私が持っているのはこれです:

from subprocess import call
call(['path_to_tool','-option1','option2'], stdout = file_out, stderr = log_file)

これは、stderrが画面に書き込まれないことを除いて、正常に機能します。もちろん、log_fileの内容を画面に出力するコードを追加することもできますが、ユーザーはそれが起こっている間ではなく、すべてが完了した後にそれを見ることができます。

要約すると、望ましい動作は次のとおりです。

  1. call()またはsubprocess()を使用します
  2. ファイルへの直接標準出力
  3. stderrをファイルに送信し、ツールがコマンドラインから直接呼び出されたかのようにstderrをリアルタイムで画面に書き込みます。

私は本当にシンプルなものを見逃している、または思ったよりもはるかに複雑な感じがします...助けてくれてありがとう!

編集:これはLinuxでのみ動作する必要があります。

26
Ben S.

Python 3。

def tee_pipe(pipe, f1, f2):
    for line in pipe:
        f1.write(line)
        f2.write(line)

proc = subprocess.Popen(["/bin/echo", "hello"],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE)

# Open the output files for stdout/err in unbuffered mode.
out_file = open("stderr.log", "wb", 0)
err_file = open("stdout.log", "wb", 0)

stdout = sys.stdout
stderr = sys.stderr

# On Python3 these are wrapped with BufferedTextIO objects that we don't
# want.
if sys.version_info[0] >= 3:
    stdout = stdout.buffer
    stderr = stderr.buffer

# Start threads to duplicate the pipes.
out_thread = threading.Thread(target=tee_pipe,
                              args=(proc.stdout, out_file, stdout))
err_thread = threading.Thread(target=tee_pipe,
                              args=(proc.stderr, err_file, stderr))

out_thread.start()
err_thread.start()

# Wait for the command to finish.
proc.wait()

# Join the pipe threads.
out_thread.join()
err_thread.join()
1
Timmmm

あなたが探しているのは次のようなものだと思います:

import sys, subprocess
p = subprocess.Popen(cmdline,
                     stdout=sys.stdout,
                     stderr=sys.stderr)

出力/ログをファイルに書き込むには、cmdlineを変更して通常のリダイレクトを含めるようにします。これは通常のlinux bash/Shellで行われます。たとえば、コマンドラインにteeを追加します:cmdline += ' | tee -a logfile.txt'

お役に立てば幸いです。

1
Brandt