2017-03-02 18 views
2

実行中のプロセスのstdoutを定期的にチェックする必要がある場合は、たとえば、プロセスはtail -f /tmp/fileで、これはpythonスクリプトで生成されます。次に、x秒ごとに、そのサブプロセスのstdoutが文字列に書き込まれ、さらに処理されます。サブプロセスは最終的にスクリプトによって停止されます。Pythonで実行中のサブプロセスのstdoutを確認する

サブプロセスのstdoutを解析するには、今までcheck_outputを使用していますが、これは動作していないようです。プロセスがまだ実行中であり、明確な出力が得られないためです。

>>> from subprocess import check_output 
>>> out = check_output(["tail", "-f", "/tmp/file"]) 
#(waiting for tail to finish) 

複数のサブプロセスの出力を処理することができるように、(例えば尾-f/TMP/FILE1、尾-f/TMP/FILE2)、サブプロセスのためのスレッドを使用することが可能であるべきです。

サブプロセスを開始し、その標準出力を定期的にチェックして処理し、最終的にはマルチスレッドのやり方でサブプロセスを停止できますか? pythonスクリプトはLinuxシステム上で動作します。

目標はファイルを連続的に読み取ることではなく、tailコマンドは使用される実際のコマンドとまったく同じように動作するため、例です。

編集:私はこれまで考えていなかったが、ファイルが存在しなかった。 check_outputは、プロセスが完了するのを単に待つだけです。

edit2:代替方法は、PopenPIPEと同じ問題が発生しているようです。 tailが終了するのを待ちます。

>>> from subprocess import Popen, PIPE, STDOUT 
>>> cmd = 'tail -f /tmp/file' 
>>> p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) 
>>> output = p.stdout.read() 
#(waiting for tail to finish) 
+0

http://stackoverflow.com/a/6482200/1866177はおそらくこの問題を解決します。 – Dschoni

+1

あなたの例はstdoutを読むことができないよりも大きな問題があります。それを修正してください。 –

+0

@Dschoni、OPは出力をリダイレクトせずに取り込みしようとしています。これにより、あなたが提供したリンクよりも少し完成したものになります。 –

答えて

4

2度目の試行は90%正しいです。唯一の問題は、すべてtailのstdoutを一度読み終えようとしていることです。しかし、tailは(?無期限)をバックグラウンドで実行するように意図されているので、あなたが本当にライン・バイ・ライン、そこから標準出力読みたい:私はshell=Trueclose_fds=True引数を削除した

from subprocess import Popen, PIPE, STDOUT 
p = Popen(["tail", "-f", "/tmp/file"], stdin=PIPE, stdout=PIPE, stderr=STDOUT) 
for line in p.stdout: 
    print(line) 

。最初のものは不要で潜在的に危険ですが、2番目のものはデフォルトです。

ファイルオブジェクトは、Pythonの行で繰り返し処理できることに注意してください。 forループは、tailのダイまで実行されますが、ではなく、tailのダイがブロックされます。

/tmp/fileに空のファイルを作成してこのプログラムを起動し、別のシェルを使用してファイルに行をエコーすると、プログラムはその行をエコーし​​ます。おそらくprintをもう少し役に立つものに置き換えるべきです。ここで

は、私は上記のコードを開始した後に入力したコマンドの例です。(別のシェルでのPythonから)

コマンドライン

$ echo a > /tmp/file 
$ echo b > /tmp/file 
$ echo c >> /tmp/file 

プログラム出力

b'a\n' 
b'tail: /tmp/file: file truncated\n' 
b'b\n' 
b'c\n' 

あなたがメインプログラムを再起動している間に反応するようにしたい場合池をtailの出力に追加するには、ループを別のスレッドで開始します。 tailが終了していなくてもプログラムが終了しないように、このスレッドをデーモンにする必要があります。スレッドにサブプロセスをオープンさせることもできますし、標準出力をスレッドに渡すこともできます。ここでのコードは、新しいスレッドを追加すると、ほぼ同じである

def deal_with_stdout(): 
    for line in p.stdout: 
     print(line) 

from subprocess import Popen, PIPE, STDOUT 
from threading import Thread 
p = Popen(["tail", "-f", "/tmp/file"], stdin=PIPE, stdout=PIPE, stderr=STDOUT) 
t = Thread(target=deal_with_stdout, daemon=True) 
t.start() 
t.join() 

:それはメインスレッドであなたより詳細に制御できますので、私は後者のアプローチを好みます。最後にjoin()を追加したので、プログラムがうまく動作するようになりました(joinはスレッドが戻る前に死ぬのを待ちます)。おそらく通常実行している処理コードで置き換えることをお勧めします。

スレッドが複雑な場合は、Threadから継承し、targetを渡す代わりにrunメソッドをオーバーライドすることもできます。

+0

よく説明してくれてありがとう、これは私を助けてくれます! –

+1

私はそれがうれしいです。マルチスレッドとマルチプロセッシングは、使い方が分かればかなり簡単なツールですが、ジャンプするのはかなり難しいです。私の最悪の部分は用語でした。 –

関連する問題