2011-02-09 27 views
15

完了するまで数分かかるプログラムを開始したいと考えています。この間、私はプログラムの進捗状況メッセージ(stdoutに表示されている)を読みたいと思います。問題は、実行中に出力を読み取る方法が見つからないということです。サブプロセスから進捗メッセージを取得する

プログラムの出力を読み取るために見つけた唯一の機能はPopen.communicate()ですが、このメソッドはプロセスが終了するまで待機します。したがって、進行状況を取得し、特殊な形式でユーザーに表示することは不可能です。

これは別の方法で行うことはできますか?

私のスクリプトでsubprocess.popenのプロセスを実行すると、画面上にプログラムの出力が表示されます。それを隠すことは可能ですか? (Ubuntu 10.10、ノーマル端末)

答えて

15

ポープンをキーワード引数stdout=subprocess.PIPEで呼び出すのが最も簡単です。

p = subprocess.Popen(["ls"], stdout=subprocess.PIPE) 
while True: 
    line = p.stdout.readline() 
    if not line: 
     break 
    print line 

ここでは、この動作を確認するには、2つのサンプルスクリプトです。

import time 
import sys 
print 10 
sys.stdout.flush() 
time.sleep(10) 
print 20 
sys.stdout.flush() 

superprint.py::それは確かに可能だ

import subprocess 
import sys 
p = subprocess.Popen(["python printandwait.py"], shell=True, stdout=subprocess.PIPE) 
while True: 
    print "Looping" 
    line = p.stdout.readline() 
    if not line: 
     break 
    print line.strip() 
    sys.stdout.flush() 
+0

whileループを壊した後にデータが到着したらどうなりますか? – Neo

+1

@Neo:彼の例はEOFで壊れています。これは、それ以降はデータが到着しないことを意味します。しかし、あなたの質問の含意に答える:stdoutパイプを読み続けることができない場合、バッファがいっぱいになり、サブプロセスがstdoutを書き込もうとするのをブロックします。 – payne

+0

p.stdoutで後で使用するのを待っています。しかし、新しい入力が到着するかパイプが閉じるまで、readlineコールはブロックされます。サンプルスクリプトをいくつか追加しました。 – chmullig

2

サブプロセスのステータスをポーリングして出力することができます。

p = subprocess.Popen('ls;sleep 10', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

rc = p.poll() 
while rc != 0: 
    while True: 
     line = p.stdout.readline() 
     if not line: 
      break 
     print line 
    rc = p.poll() 

assert rc == 0 
1

:私のパッケージまさにこれを行いpython-gnupggpg産卵(python superprint.py

printandwait.py同じディレクトリにそれらの両方を作成し、実行しますGnuプライバシーガード)をサブプロセスで実行します。一般的なケースでは、サブプロセスのstdoutとstderrにはsubprocess.PIPEを指定する必要があります。 2つの別々のスレッドを作成して、stdoutとstderrのサブプロセスを好きな場所に読み込みます。

python-gnupgの場合、gpgプロセスが実行されている間(完了するまで待機していない)、gpgからのステータスメッセージが読み込まれ、処理されます。

基本的には、擬似コードは

process = subprocess.Popen(..., stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
stderr = process.stderr 
rr = threading.Thread(target=response_reader_func, args=(process.stderr,)) 
rr.setDaemon(True) 
rr.start() 

dr = threading.Thread(target=data_reader_func, args=(process.stdout,)) 
dr.setDaemon(True) 
dr.start() 

dr.join() 
rr.join() 
process.wait() 

リーダー機能が(何らかの方法で進捗情報を更新する、あなたのケースでは)一般的に、彼らが読んでいるものに基づいて正しいことを行う囲むクラスのメソッドですです。

関連する問題