2016-12-22 7 views
0

stderrとstdoutを複数のファイルにリダイレクトしたいだけです。 例: stderrはfile_1とfile_2にリダイレクトされます。pythonのサブプロセスstderrとstdoutを複数のファイルにリダイレクトする方法は?

私は出力を1つのファイルにリダイレクトするために以下を使用しています。事の上

subprocess.Popen("my_commands",shell=True,stdout=log_file,stderr=err_file,executable="/bin/bash") 

単一のファイルにstdoutstderrをリダイレクトします。
は誰もが同じことを行う方法を教えてもらえます(両方のファイルに出力をリダイレクトしlog_fileとERR_FILE例えばstdout log_fileとERR_FILEとstderrがERR_FILEにリダイレクトする必要があるとNEW_FILEの両方にリダイレクトする必要があります)あなたは、あなた自身のファイルのようなクラスを作成することができます

+0

いくつかの回答が参考になります:http://stackoverflow.com/questions/2996887/how-to-replicate-tee-behavior-in-python-when-using-subprocess –

+0

あなたは私に私が使っていたものと同じです。しかし、それは複数のファイル記述子にリダイレクトする必要があります。単一のファイルだけでなく、 – Swapnil

+0

有用ではありません。 Not working – Swapnil

答えて

1

複数のファイルハンドルに書き込みます。ここに簡単な例があり、sys.stdoutsys.stderrのリダイレクトテストがあります。そのコードを実行した後

import sys 

class MultiOut(object): 
    def __init__(self, *args): 
     self.handles = args 

    def write(self, s): 
     for f in self.handles: 
      f.write(s) 

with open('q1', 'w') as f1, open('q2', 'w') as f2, open('q3', 'w') as f3: 
    sys.stdout = MultiOut(f1, f2) 
    sys.stderr = MultiOut(f3, f2) 
    for i, c in enumerate('abcde'): 
     print(c, 'out') 
     print(i, 'err', file=sys.stderr) 

は、ここではそれらのファイルが含まれているものです:

Q1

a out 
b out 
c out 
d out 
e out  

Q3

0 err 
1 err 
2 err 
3 err 
4 err  

Q2

a out 
0 err 
b out 
1 err 
c out 
2 err 
d out 
3 err 
e out 
4 err 

FWIWあなたが好きならば、あなたも、これを行うことができます:Popenので残念ながら、MultiOutのようなファイルのようなオブジェクトがPopenで使用することはできません

sys.stdout = MultiOut(f1, f2, sys.stdout) 
sys.stderr = MultiOut(f3, f2, sys.stderr) 

を基礎となるOSファイルディスクリプタを介してファイルにアクセスします。つまり、OSがファイルとみなすものが必要なため、有効なを提供するPythonオブジェクトだけですメソッドは、Popenのファイル引数に使用できます。

代わりに、Python 3のasyncio機能を使用して、シェルコマンドを実行し、stdoutとstderrの出力を同時にコピーすることができます。

まず、以下のPythonコードをテストするために使用した単純なBashスクリプトを示します。以前のPythonの例のように、配列の内容をstdoutに、配列のインデックスをstderrにエコーします。

multitest.bsh

#!/usr/bin/env bash 

a=(a b c d e) 
for((i=0; i<${#a[@]}; i++)) 
do 
    echo "OUT: ${a[i]}" 
    echo "ERR: $i" >&2 
    sleep 0.01 
done 

出力

OUT: a 
ERR: 0 
OUT: b 
ERR: 1 
OUT: c 
ERR: 2 
OUT: d 
ERR: 3 
OUT: e 
ERR: 4 

そして、ここでPythonの3つのファイルのQ1とQ2にその標準出力の出力をパイプ、multitest.bsh実行されるコード、およびその標準エラー出力ですq3とq2に出力する。コードを実行した後

import asyncio 
from asyncio.subprocess import PIPE 

class MultiOut(object): 
    def __init__(self, *args): 
     self.handles = args 

    def write(self, s): 
     for f in self.handles: 
      f.write(s) 

    def close(self): 
     pass 

@asyncio.coroutine 
def copy_stream(stream, outfile): 
    """ Read from stream line by line until EOF, copying it to outfile. """ 
    while True: 
     line = yield from stream.readline() 
     if not line: 
      break 
     outfile.write(line) # assume it doesn't block 

@asyncio.coroutine 
def run_and_pipe(cmd, fout, ferr): 
    # start process 
    process = yield from asyncio.create_subprocess_shell(cmd, 
     stdout=PIPE, stderr=PIPE, executable="/bin/bash") 

    # read child's stdout/stderr concurrently 
    try: 
     yield from asyncio.gather(
      copy_stream(process.stdout, fout), 
      copy_stream(process.stderr, ferr)) 
    except Exception: 
     process.kill() 
     raise 
    finally: 
     # wait for the process to exit 
     rc = yield from process.wait() 
    return rc 

# run the event loop 
loop = asyncio.get_event_loop() 

with open('q1', 'wb') as f1, open('q2', 'wb') as f2, open('q3', 'wb') as f3: 
    fout = MultiOut(f1, f2) 
    ferr = MultiOut(f3, f2) 
    rc = loop.run_until_complete(run_and_pipe("./multitest.bsh", fout, ferr)) 
loop.close() 
print('Return code:', rc)  

は、ここではそれらのファイルが含まれているものです:

Q1

OUT: a 
OUT: b 
OUT: c 
OUT: d 
OUT: e 

Q3

ERR: 0 
ERR: 1 
ERR: 2 
ERR: 3 
ERR: 4 

Q2

OUT: a 
ERR: 0 
OUT: b 
ERR: 1 
OUT: c 
ERR: 2 
OUT: d 
ERR: 3 
OUT: e 
ERR: 4 

asyncioコードは、質問Subprocess.Popen: cloning stdout and stderr both to terminal and variablesJ.F. Sebastian's answerから持ち上げました。ありがとう、J.F!

スケジュールされたコルーチンが利用できるようになると、ファイルにデータが書き込まれることに注意してください。正確にの場合、が発生した場合は、現在のシステム負荷によって異なります。ですから、sleep 0.01コマンドをmultitest.bshに入れて、stdoutとstderrの行を同期させた状態にしておきます。この遅れがなければ、q2のstdoutとstderrの行は一般的にうまくインターリーブされません。その同期を達成するためのより良い方法があるかもしれませんが、私はまだasyncioプログラミングの初心者です。

+0

これは私にとってはうまくいかないでしょう。あなたはサブプロセスと同じことを提案できますか?ありがとう。 – Swapnil

+0

@Swapnil申し訳ありません!私は 'Popen'が基礎となるOSファイルを介してファイルにアクセスするため、' AttributeError: 'MultiOut'オブジェクトに属性 'fileno'エラーがないのを理由に、これが 'Popen'で動作しないことを知りました。あなたが望むものは可能ですが、ちょっとトリッキーですが、私は現在様々な解決策を探しています。 –

+0

@Swapnil最新の回答をご覧ください。 –

関連する問題