2011-03-02 18 views
8

私のpythonスクリプトはサブプロセスを使って別のスクリプトを呼び出し、非常に遅い(行単位で)出力を生成します。私は出力を行ごとにファイルに書きたいと思います。プロセス全体が終了し、出力全体を文字列として書き込みます。次のコードは、「スクリプト」が終了したときに出力を「ファイル」に書き込みます。subprocess.Popenからstdoutを行ごとに保存

args = ("script") 
file = open('output.txt', 'w') 
subprocess.Popen(args,stdout=file) 

でも可能ですか? Thanx、Chris

答えて

1

はい、可能です。ここでは、Pythonシェルスクリプトの単体テストを行うためにテストハーネスを使用するために書いた関数を示します。

def testrun(cmdline): 
    try: 
     cmdout, cmderr = "","" 
     cmdp = Popen(cmdline, shell=True,stdout=PIPE, stderr=PIPE) 
     cmdout,cmderr = cmdp.communicate() 
     retcode = cmdp.wait() 
     if retcode < 0: 
     print >>sys.stderr, "Child was terminated by signal", -retcode 
     else: 
     return (retcode,cmdout,cmderr) 
    except OSError, e: 
     return (e,cmdout,cmderr) 

機能はsys.exit()によってシェルリターンコードの問題を含んでいるタプル、標準出力テキスト、および標準エラー出力テキストを返します。これらは両方ともテキスト文字列なので、処理する前に行に分割するにはsplitlinesを使用する必要があります。

実際に出力と対話する必要がある場合は、subprocessモジュールではなくpexpectを使用する方がよいでしょう。

+0

あなたはpexpectを使った例を与えることができますか? – perimosocordiae

+0

あなたはpexpectのウェブサイトに行きましたか?セクション8は、その使用方法のいくつかの例を示しています。 –

0

私は私が働いているプログラミング言語で同じ問題を抱えていたし、これをやってしまった:https://github.com/perimosocordiae/plumbum/blob/master/lib/stdlib.py#L21

は残念ながら、それがされるまでのラインを蓄積し、一度に文字を出力ストリームからの読み込みを必要とします改行が見つかりました。しかし、それは動作し、私は同じ振る舞いを得る他の方法を知らない。

+0

私の答えに追加したpexpectリンクを確認してください。 –

+0

pexpectはまだpy3kと互換性がないようです。 – perimosocordiae

2

あなたが行ずつ、それとの対話を試みることができるようにあなたはポールを使用してプロセスと対話することができます

process = subprocess.Popen(["ls", "-lart"], 
       bufsize=-1, # fully buffered (default) 
       stdin=subprocess.PIPE, 
       stdout=subprocess.PIPE, 
       stderr=subprocess.PIPE, 
       cwd=os.curdir, 
       env=os.environ) 
my_stdout_file = open("stdout.txt", "w") 
while True: 
    process.poll() 
    line = process.stdout.readline() 
    my_stdout_file.write(line) 
    eline = process.stderr.readline() 
    if line: 
     stdout_lines.append(line) 
    if eline: 
     stderr_lines.append(eline) 
    if (line == "" and eline == "" and 
     process.returncode != None): 
     break 
1

思想私にはないソリューションを共有したい:例えば

.poll()、.wait()、.communicate()を使用してください。ポイントのカップル:

  • 私の出力が東アジアUTF-8テキスト
  • Iトラップ私は'\x0a'を使用し、破損/無効なUTF-8テキスト
  • をフィルタリングするtry:と各ラインを含んでいるので、私はimport codecsを使用プラットフォームに関係なくLinuxの改行を強制する。
  • 使用for line in iter(subproc.stderr.readline, ''):あなたはstderrの
  • をキャプチャする必要がある場合は、このアプローチは、子プログラムはキロワットの辞書を使用して出力
  • を作成した場合にのみ出力を生成すると、この例ではやり過ぎですが、サブプロセス
と** kwargsからを使用する方法を示します

コード:

import subprocess 
import codecs 
import os 

kw = { 
    'bufsize': 0, 
    'executable': None, 
    'stdin': subprocess.PIPE, 
    'stdout': subprocess.PIPE, 
    'stderr': subprocess.PIPE, 
    'preexec_fn': None, 
    'close_fds': False, 
    'shell': False, 
    'cwd': None, 
    'env': None, 
    'universal_newlines': False, 
    'startupinfo': None, 
    'creationflags': 0, 
    } 

args = ['ls', '-lart'] 
kw['cwd'] = os.path.expanduser('~') 
logfile = os.path.expanduser('~/stdout.txt') 
stdlog = [] 

try: 
    subproc = subprocess.Popen(args,**kw) 
except: 
    print 'Error loading subprocess. Check arguments and kwargs' 
    exit() 

log = codecs.open(logfile,'w','utf-8') 
log.write(': Starting log for: \"%s\"\x0a'%(' '.join(args))) 
for line in iter(subproc.stdout.readline, ''): 
    try: 
     stdlog.append(line.rstrip().decode('utf-8')) 
     log.write(stdout[-1]+'\x0a') 
     print stdout[-1] 
    except: 
     pass 

log.flush() 
log.close() 
関連する問題