55

Popenを使用して、stdoutとstderrをログファイルに継続的に書き込んでいるシェルスクリプトを呼び出しています。ログファイルを連続して(画面に)同時に出力する方法、またはシェルスクリプトにログファイルとstdoutの両方に同時に書き込む方法はありますか?

私は基本的にPythonで次のようなことをしたいと思っています:

cat file 2>&1 | tee -a logfile #"cat file" will be replaced with some script

繰り返しますが、これはstderr / stdoutを一緒にteeにパイプし、それをstdoutと私のログファイルの両方に書き込みます。

Pythonでstdoutとstderrをログファイルに書き込む方法を知っています。私が立ち往生しているのは、これらを画面に複製する方法です。

subprocess.Popen("cat file", shell=True, stdout=logfile, stderr=logfile)

もちろん、私はこのようなことをすることができますが、teeとシェルのファイル記述子のリダイレクトなしでこれを行う方法はありますか?:

subprocess.Popen("cat file 2>&1 | tee -a logfile", shell=True)
4

3 に答える 3

53

パイプを使用して、プログラムのstdoutからデータを読み取り、必要なすべての場所に書き込むことができます。

import sys
import subprocess

logfile = open('logfile', 'w')
proc=subprocess.Popen(['cat', 'file'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in proc.stdout:
    sys.stdout.write(line)
    logfile.write(line)
proc.wait()

アップデート

Python 3では、universal_newlinesパラメーターはパイプの使用方法を制御します。の場合False、パイプは戻りオブジェクトを読み取り、文字列を取得するbytesためにデコードする必要がある場合があります(たとえばline.decode('utf-8'))。の場合True、Pythonがデコードを行います

バージョン3.3で変更:universal_newlinesがTrueの場合、クラスはlocale.getpreferredencoding()ではなくエンコーディングlocale.getpreferredencoding(False)を使用します。この変更の詳細については、io.TextIOWrapperクラスを参照してください。

于 2013-03-20T21:46:35.577 に答える
18

エミュレートするには:コマンドsubprocess.call("command 2>&1 | tee -a logfile", shell=True)を呼び出さずに:tee

#!/usr/bin/env python2
from subprocess import Popen, PIPE, STDOUT

p = Popen("command", stdout=PIPE, stderr=STDOUT, bufsize=1)
with p.stdout, open('logfile', 'ab') as file:
    for line in iter(p.stdout.readline, b''):
        print line,  #NOTE: the comma prevents duplicate newlines (softspace hack)
        file.write(line)
p.wait()

考えられるバッファリングの問題 (出力が遅延している場合) を修正するには、Python のリンクを参照してください: subprocess.communicate() からストリーミング入力を読み取ります

Python 3 バージョンは次のとおりです。

#!/usr/bin/env python3
import sys
from subprocess import Popen, PIPE, STDOUT

with Popen("command", stdout=PIPE, stderr=STDOUT, bufsize=1) as p, \
     open('logfile', 'ab') as file:
    for line in p.stdout: # b'\n'-separated lines
        sys.stdout.buffer.write(line) # pass bytes as is
        file.write(line)
于 2016-01-05T05:22:58.107 に答える