8

perl でいくつかのシェル コマンドをパイプするのと同等の python を使用したかったのです。open(PIPE, "command |") の Python バージョンのようなもの。

subprocess モジュールに移動して、これを試します。

p = subprocess.Popen("zgrep thingiwant largefile", shell=True, stdout=subprocess.PIPE)

これは、perl で行うのと同じ方法で出力を読み取るために機能しますが、それ自体はクリーンアップしません。インタープリターを終了すると、

grep: writing output: Broken pipe

stderr 全体に数百万回吐き出しました。私は単純に、これがすべて解決されることを望んでいたと思いますが、そうではありません。p で terminate または kill を呼び出しても効果がないようです。プロセス テーブルを見てください。これにより /bin/sh プロセスが強制終了されますが、破損したパイプについて文句を言うために子の gzip はそのまま残されます。

これを行う正しい方法は何ですか?

4

4 に答える 4

11

問題は、pipeがいっぱいだということです。サブプロセスは停止し、パイプが空になるのを待ちますが、その後、プロセス (Python インタープリター) が終了し、パイプの終わりが壊れます (したがって、エラー メッセージが表示されます)。

p.wait()あなたを助けません:

警告子プロセスが stdout または stderr パイプに十分な出力を生成し、OS パイプ バッファーがさらにデータを受け入れるのを待ってブロックする場合、これはデッドロックになります。communicate()それを回避するために使用します。

http://docs.python.org/library/subprocess.html#subprocess.Popen.wait

p.communicate()あなたを助けません:

読み取ったデータはメモリにバッファリングされるため、データ サイズが大きい場合や無制限の場合は、このメソッドを使用しないでください。

http://docs.python.org/library/subprocess.html#subprocess.Popen.communicate

p.stdout.read(num_bytes)あなたを助けません:

警告communicate()またはではなく.stdin.write.stdout.readまたはを使用.stderr.readして、他の OS パイプ バッファがいっぱいになり、子プロセスをブロックすることによるデッドロックを回避します。

http://docs.python.org/library/subprocess.html#subprocess.Popen.stdout

この話の教訓は、大規模な出力のsubprocess.PIPE場合、プログラムがデータを読み取ろうとすると、特定の失敗につながるということです (ループに入れることができるはずですp.stdout.read(bytes)while p.returncode is None:、上記の警告は、これが可能性があることを示唆しています)。デッドロック)。

ドキュメントは、シェルパイプをこれに置き換えることを提案しています:

p1 = Popen(["zgrep", "thingiwant", "largefile"], stdout=PIPE)
p2 = Popen(["processreceivingdata"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

p2が標準入力を から直接取得していることに注意してくださいp1。これはデッドロックを回避するはずですが、上記の矛盾した警告を考えると .

とにかく、その最後の部分がうまくいかない場合 (ただし、そうあるべきです)、一時ファイルを作成し、最初の呼び出しからすべてのデータを書き込み、一時ファイルを次のプロセスへの入力として使用することができます。

于 2010-04-08T20:41:33.653 に答える
3

パイプを開いた後、コマンド出力を操作できます: p.stdout:

for line in p.stdout:
    # do stuff
p.stdout.close()
于 2010-04-08T00:05:41.333 に答える
0

waitプロセスを完了するには、次のことが必要です。

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True)
p.wait()

または、プログラムの標準出力 (お持ちのとおり) と、おそらくその標準エラーをキャプチャしてから、次のように呼び出すことができますcommunicate

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True,
                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
于 2010-04-08T20:21:31.580 に答える
0

このプロセスをどのように実行しましたか?

適切な方法は使用することです

p.communicate()

詳細については、ドキュメントを参照してください。

于 2010-04-07T20:25:02.597 に答える