34

私はPythonでサブプロセスパイプラインをテストしています。以下のプログラムがPythonで直接実行できることは承知していますが、それは重要ではありません。パイプラインをテストしたいので、使用方法を知っています。

私のシステムはLinuxUbuntu9.04で、デフォルトはpython2.6です。

私はこのドキュメントの例から始めました。

from subprocess import Popen, PIPE
p1 = Popen(["grep", "-v", "not"], stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]
print output

それは機能しますが、p1'sstdinはリダイレクトされていないため、パイプにフィードするためにターミナルに入力する必要があります。^D終了stdinと入力すると、必要な出力が得られます。

ただし、Python文字列変数を使用してパイプにデータを送信したいと思います。最初に私はstdinに書いてみました:

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)
p1.stdin.write('test\n')
output = p2.communicate()[0] # blocks forever here

動作しませんでした。p2.stdout.read()最後の行で代わりに使用してみましたが、ブロックされます。追加p1.stdin.flush()しましp1.stdin.close()たが、どちらも機能しませんでした。それから私はコミュニケーションに移りました:

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)
p1.communicate('test\n') # blocks forever here
output = p2.communicate()[0] 

だから、それはまだそれではありません。

単一のプロセスの実行(p1上記のように、削除p2)が完全に機能することに気づきました。p1また、ファイルハンドルを( )に渡すこともできますstdin=open(...)。したがって、問題は次のとおりです。

ブロッキングせずに、Pythonで2つ以上のサブプロセスのパイプラインにデータを渡すことは可能ですか?なぜだめですか?

シェルを実行してパイプラインをシェルで実行できることは承知していますが、それは私が望んでいることではありません。


更新1:以下のAaron Digullaのヒントに従って、スレッドを使用して機能させようとしています。

まず、スレッドでp1.communicateを実行してみました。

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)
t = threading.Thread(target=p1.communicate, args=('some data\n',))
t.start()
output = p2.communicate()[0] # blocks forever here

さて、動作しませんでした。に変更するなど、他の組み合わせも試してみまし.write()p2.read()。何もない。次に、反対のアプローチを試してみましょう。

def get_output(subp):
    output = subp.communicate()[0] # blocks on thread
    print 'GOT:', output

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)
t = threading.Thread(target=get_output, args=(p2,)) 
t.start()
p1.communicate('data\n') # blocks here.
t.join()

コードはどこかでブロックされてしまいます。生成されたスレッド、メインスレッド、またはその両方。だからそれはうまくいきませんでした。それを機能させる方法を知っているなら、機能するコードを提供できればもっと簡単になるでしょう。私はここで試しています。


更新2

Paul Du Boisがいくつかの情報で以下に答えたので、私はさらにテストを行いました。モジュール全体を読み、subprocess.pyそれがどのように機能するかを理解しました。だから私はそれをコードに正確に適用してみました。

私はLinuxを使用していますが、スレッドを使用してテストしていたため、最初のアプローチは、subprocess.pycommunicate()メソッドで見られる正確なWindowsスレッドコードを複製することでしたが、1つではなく2つのプロセスでした。これが私が試したものの完全なリストです:

import os
from subprocess import Popen, PIPE
import threading

def get_output(fobj, buffer):
    while True:
        chunk = fobj.read() # BLOCKS HERE
        if not chunk:
            break
        buffer.append(chunk)

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)

b = [] # create a buffer
t = threading.Thread(target=get_output, args=(p2.stdout, b))
t.start() # start reading thread

for x in xrange(100000):
    p1.stdin.write('hello world\n') # write data
    p1.stdin.flush()
p1.stdin.close() # close input...
t.join()

上手。うまくいきませんでした。p1.stdin.close()呼び出された後も、p2.stdout.read()まだブロックします。

次に、posixコードを試してみましたsubprocess.py

import os
from subprocess import Popen, PIPE
import select

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)

numwrites = 100000
to_read = [p2.stdout]
to_write = [p1.stdin]
b = [] # create buffer

while to_read or to_write:
    read_now, write_now, xlist = select.select(to_read, to_write, [])
    if read_now:
        data = os.read(p2.stdout.fileno(), 1024)
        if not data:
            p2.stdout.close()
            to_read = []
        else:
            b.append(data)

    if write_now:
        if numwrites > 0:
            numwrites -= 1
            p1.stdin.write('hello world!\n'); p1.stdin.flush()
        else:
            p1.stdin.close()
            to_write = []

print b

また、をブロックしselect.select()ます。sを広めることによってprint、私はこれを見つけました:

  • 読書は機能しています。コードは実行中に何度も読み取ります。
  • ライティングも機能しています。データはに書き込まれp1.stdinます。
  • の終わりにnumwritesp1.stdin.close()が呼び出されます。
  • select()ブロックを開始すると、何かしかありto_readませんp2.stdoutto_writeすでに空です。
  • os.read()callは常に何かを返すため、p2.stdout.close()呼び出されることはありません。

両方のテストからの結論stdin:(例では)パイプラインの最初のプロセスを閉じることはgrep、バッファリングされた出力を次のプロセスにダンプして死ぬことにはなりません。

それを機能させる方法はありませんか?

PS:一時ファイルは使いたくありません。すでにファイルでテストしていて、動作することはわかっています。そして、私はウィンドウを使いたくありません。

4

11 に答える 11

22

私はそれを行う方法を見つけました。

それはスレッドについてではなく、select()についてでもありません。

最初のプロセス(grep)を実行すると、パイプごとに1つずつ、2つの低レベルのファイル記述子が作成されます。それらaをと呼びましょうb

2番目のプロセスを実行すると、bに渡されcut sdtinます。Popenしかし、 -には脳死のデフォルトがありますclose_fds=False

その効果は、cutも継承することaです。stdinはまだのプロセスで開いているので(無視します) 、grep閉じても死ぬことはできません。acutcut

次のコードは完全に実行されます。

from subprocess import Popen, PIPE

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE, close_fds=True)
p1.stdin.write('Hello World\n')
p1.stdin.close()
result = p2.stdout.read() 
assert result == "Hello Worl\n"

close_fds=TrueUNIXシステムではデフォルトである必要があります。Windowsでは、すべてのfdsを閉じるため、配管が防止されます。

編集:

PS:この回答を読んで同様の問題を抱えている人のために:pooryorickがコメントで言ったように、書き込まれるデータがp1.stdinバッファーよりも大きい場合もブロックされる可能性があります。その場合、データをより小さな部分にチャンクし、select.select()いつ読み取り/書き込みするかを知るために使用する必要があります。問題のコードは、それを実装する方法についてのヒントを与えるはずです。

EDIT2:pooryorickの助けを借りて、別の解決策を見つけました-すべてのfdsを使用して閉じる代わりにclose_fds=True 2番目のプロセスを実行するときに最初のプロセスに属するsを閉じることができ、それは機能します。クロージングは​​子で行う必要があるため、Popenの関数はそれを行うのに非常に便利です。p2を実行すると、次のことができます。fdpreexec_fn

p2 = Popen(cmd2, stdin=p1.stdout, stdout=PIPE, stderr=devnull, preexec_fn=p1.stdin.close)
于 2009-10-23T23:33:38.893 に答える
7

大きなファイルでの作業

Pythonで大きなファイルを操作する場合は、2つの原則を一律に適用する必要があります。

  1. どのIOルーチンもブロックできるため、パイプラインの各ステージを異なるスレッドまたはプロセスに保持する必要があります。この例ではスレッドを使用していますが、サブプロセスを使用するとGILを回避できます。
  2. 進行を開始する前に待機しないように、増分読み取りと書き込みを使用する必要があります。EOF

別の方法は、ノンブロッキングIOを使用することですが、これは標準のPythonでは面倒です。非ブロッキングプリミティブを使用して同期IOAPIを実装する軽量スレッドライブラリについては、geventを参照してください。

サンプルコード

おおざっぱな愚かなパイプラインを構築します

{cat /usr/share/dict/words} | grep -v not              \
    | {upcase, filtered tee to stderr} | cut -c 1-10   \
    | {translate 'E' to '3'} | grep K | grep Z | {downcase}

中括弧内の各ステージは{}Pythonで実装され、他のステージは標準の外部プログラムを使用します。TL; DR: この要点を参照してください

予想される輸入から始めます。

#!/usr/bin/env python
from subprocess import Popen, PIPE
import sys, threading

パイプラインのPythonステージ

パイプラインのPythonで実装された最後のステージを除くすべてのステージは、IOが他のステージをブロックしないように、スレッドに入れる必要があります。これらを実際に並列で実行したい場合は、代わりにPythonサブプロセスで実行できます(GILを回避します)。

def writer(output):
    for line in open('/usr/share/dict/words'):
        output.write(line)
    output.close()
def filter(input, output):
    for line in input:
        if 'k' in line and 'z' in line: # Selective 'tee'
            sys.stderr.write('### ' + line)
        output.write(line.upper())
    output.close()
def leeter(input, output):
    for line in input:
        output.write(line.replace('E', '3'))
    output.close()

これらはそれぞれ独自のスレッドに入れる必要があります。これは、この便利な関数を使用して行います。

def spawn(func, **kwargs):
    t = threading.Thread(target=func, kwargs=kwargs)
    t.start()
    return t

パイプラインを作成する

を使用して外部ステージを作成し、を使用PopenしてPythonステージを作成しますspawn。引数bufsize=-1は、システムのデフォルトのバッファリング(通常は4kiB)を使用することを示しています。これは通常、デフォルト(バッファなし)またはラインバッファリングよりも高速ですが、ラグなしで出力を視覚的に監視する場合は、ラインバッファリングが必要になります。

grepv   = Popen(['grep','-v','not'], stdin=PIPE, stdout=PIPE, bufsize=-1)
cut     = Popen(['cut','-c','1-10'], stdin=PIPE, stdout=PIPE, bufsize=-1)
grepk = Popen(['grep', 'K'], stdin=PIPE, stdout=PIPE, bufsize=-1)
grepz = Popen(['grep', 'Z'], stdin=grepk.stdout, stdout=PIPE, bufsize=-1)

twriter = spawn(writer, output=grepv.stdin)
tfilter = spawn(filter, input=grepv.stdout, output=cut.stdin)
tleeter = spawn(leeter, input=cut.stdout, output=grepk.stdin)

パイプラインを駆動する

上記のように組み立てると、パイプライン内のすべてのバッファーがいっぱいになりますが、最後()から誰も読み取っていないため、grepz.stdoutすべてブロックされます。を1回呼び出すだけですべてを読み取ることができますがgrepz.stdout.read()、大きなファイルには大量のメモリが使用されます。代わりに、段階的に読み取ります

for line in grepz.stdout:
    sys.stdout.write(line.lower())

スレッドとプロセスは、に達するとクリーンアップされますEOF。を使用して明示的にクリーンアップできます

for t in [twriter, tfilter, tleeter]: t.join()
for p in [grepv, cut, grepk, grepz]: p.wait()

Python-2.6以前

内部的には、をsubprocess.Popen呼び出しfork、パイプファイル記述子を構成し、を呼び出しますexec。からの子プロセスforkには、親プロセス内のすべてのファイル記述子のコピーがあり、対応するリーダーがを取得する前に、両方のコピーを閉じる必要がありますEOF。これは、パイプを手動で閉じるか(close_fds=Trueまたはの適切なpreexec_fn引数によって)、またはファイル記述子を自動的に閉じるようにフラグをsubprocess.Popen設定することで修正できます。このフラグはPython-2.7以降で自動的に設定されます。issue12786を参照してください。以前のバージョンのPythonでPython-2.7の動作を取得するには、FD_CLOEXECexec

p._set_cloexec_flags(p.stdin)

p.stdin引数として後続のに渡す前subprocess.Popen

于 2012-12-27T20:49:46.720 に答える
3

パイプを期待どおりに機能させるための3つの主なトリックがあります

  1. パイプの両端が異なるスレッド/プロセスで使用されていることを確認してください(上部にある例のいくつかはこの問題に悩まされています)。

  2. 各プロセスでパイプの未使用の端を明示的に閉じます

  3. バッファリングを無効にする(Python -uオプション)か、ptyを使用するか、データに影響を与えないもの(おそらく'\ n'ですが、適切なもの)でバッファを埋めることによってバッファリングを処理します。

Pythonの「パイプライン」モジュール(私は作成者です)の例は、シナリオに正確に適合し、低レベルの手順をかなり明確にします。

http://pypi.python.org/pypi/pipeline/

最近では、サブプロセスモジュールをプロデューサー-プロセッサー-コンシューマー-コントローラーパターンの一部として使用しました。

http://www.darkarchive.org/w/Pub/PythonInteract

この例では、ptyを使用せずにバッファリングされたstdinを扱い、どのパイプの端をどこで閉じる必要があるかも示しています。私はスレッド化よりもプロセスを好みますが、原則は同じです。さらに、プロデューサーにフィードし、コンシューマーから出力を収集するキューの同期と、それらをクリーンにシャットダウンする方法を示します(キューに挿入されたセンチネルに注意してください)。このパターンにより、最近の出力に基づいて新しい入力を生成できるため、再帰的な検出と処理が可能になります。

于 2010-01-31T20:12:58.360 に答える
3

Noskloが提供するソリューションは、パイプの受信側に書き込まれるデータが多すぎるとすぐに壊れます。


from subprocess import Popen, PIPE

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE, close_fds=True)
p1.stdin.write('Hello World\n' * 20000)
p1.stdin.close()
result = p2.stdout.read() 
assert result == "Hello Worl\n"

このスクリプトがマシンでハングしない場合は、「20000」をオペレーティングシステムのパイプバッファのサイズを超える値に増やしてください。

これは、オペレーティングシステムが入力を「grep」にバッファリングしているためですが、そのバッファがいっぱいになると、p1.stdin.writeから何かが読み取られるまで呼び出しがブロックされp2.stdoutます。おもちゃのシナリオでは、同じプロセスでパイプへの書き込み/パイプからの読み取りを行うことができますが、通常の使用法では、1つのスレッド/プロセスから書き込み、別のスレッド/プロセスから読み取る必要があります。これは、subprocess.popen、os.pipe、os.popen*などに当てはまります。

もう1つの工夫は、同じパイプの以前の出力から生成されたアイテムをパイプに供給し続けたい場合があることです。解決策は、パイプフィーダーとパイプリーダーの両方をmanプログラムと非同期にし、2つのキューを実装することです。1つはメインプログラムとパイプフィーダーの間、もう1つはメインプログラムとパイプリーダーの間です。 PythonInteractはその一例です。

サブプロセスは便利なモデルですが、os.popenとos.forkの呼び出しの詳細が内部に隠されているため、使用する下位レベルの呼び出しよりも処理が難しい場合があります。このため、サブプロセスは、プロセス間パイプが実際にどのように機能するかを知るための良い方法ではありません。

于 2010-02-08T16:30:25.503 に答える
2

これは、いくつかのスレッドで行う必要があります。そうしないと、データを送信できない状況になります。p2の出力を読み取らないため、p2はp1の出力を読み取らないため、子p1は入力を読み取れません。

したがって、p2が書き出すものを読み取るバックグラウンドスレッドが必要です。これにより、パイプにデータを書き込んだ後もp2を続行できるため、p1から次の入力行を読み取ることができます。これにより、p1は送信したデータを処理できます。

または、バックグラウンドスレッドを使用してデータをp1に送信し、メインスレッドでp2からの出力を読み取ることもできます。ただし、どちらの側もスレッドである必要があります。

于 2009-10-20T15:41:29.723 に答える
2

なしでは実行できないというnoskloの主張(この質問に対する他のコメントを参照)への応答close_fds=True

close_fds=True他のファイル記述子を開いたままにしておく場合にのみ必要です。複数の子プロセスを開くときは、継承される可能性のある開いているファイルを追跡し、不要なファイルを明示的に閉じることをお勧めします。

from subprocess import Popen, PIPE

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p1.stdin.write('Hello World\n')
p1.stdin.close()
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)
result = p2.stdout.read() 
assert result == "Hello Worl\n"

close_fdsFalseサブプロセスは、開いているファイル記述子で何をしているのかを知るために呼び出し元のプログラムを信頼し、それが必要な場合は呼び出し元にすべてを閉じる簡単なオプションを提供することを好むため、デフォルトはになります。

しかし、本当の問題は、おもちゃの例を除いて、パイプバッファがあなたを噛むことです。この質問に対する他の回答で述べたように、経験則では、リーダーとライターを同じプロセス/スレッドで開かないようにします。サブプロセスモジュールを双方向通信に使用したい場合は、最初にos.pipeとos.forkを学習することをお勧めします。良い例があれば、実際にはそれほど難しくはありません。

于 2010-02-10T20:49:51.323 に答える
1

上記のコメントの1つで、私はnoskloに、彼の主張を裏付けるためのコードを投稿するか、select.select以前に反対票を投じた私の回答に賛成するように要求しました。彼は次のコードで応答しました。

from subprocess import Popen, PIPE
import select

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE, close_fds=True)

data_to_write = 100000 * 'hello world\n'
to_read = [p2.stdout]
to_write = [p1.stdin]
b = [] # create buffer
written = 0


while to_read or to_write:
    read_now, write_now, xlist = select.select(to_read, to_write, [])
    if read_now:
        data = p2.stdout.read(1024)
        if not data:
            p2.stdout.close()
            to_read = []
        else:
            b.append(data)

    if write_now:
        if written < len(data_to_write):
            part = data_to_write[written:written+1024]
            written += len(part)
            p1.stdin.write(part); p1.stdin.flush()
        else:
            p1.stdin.close()
            to_write = []

print b

このスクリプトの問題の1つは、システムパイプバッファのサイズ/性質を2番目に推測することです。1024のようなマジックナンバーを削除できれば、スクリプトの失敗は少なくなります。

大きな問題は、このスクリプトコードが、データ入力と外部プログラムの正しい組み合わせでのみ一貫して機能することです。grepとcutはどちらも行で機能するため、それらの内部バッファーの動作は少し異なります。「cat」のようなより一般的なコマンドを使用し、パイプに小さなデータを書き込むと、致命的な競合状態がより頻繁に発生します。

from subprocess import Popen, PIPE
import select
import time

p1 = Popen(["cat"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cat"], stdin=p1.stdout, stdout=PIPE, close_fds=True)

data_to_write = 'hello world\n'
to_read = [p2.stdout]
to_write = [p1.stdin]
b = [] # create buffer
written = 0


while to_read or to_write:
    time.sleep(1)
    read_now, write_now, xlist = select.select(to_read, to_write, [])
    if read_now:
        print 'I am reading now!'
        data = p2.stdout.read(1024)
        if not data:
            p1.stdout.close()
            to_read = []
        else:
            b.append(data)

    if write_now:
        print 'I am writing now!'
        if written < len(data_to_write):
            part = data_to_write[written:written+1024]
            written += len(part)
            p1.stdin.write(part); p1.stdin.flush()
        else:
            print 'closing file'
            p1.stdin.close()
            to_write = []

print b

この場合、2つの異なる結果が現れます。

write, write, close file, read -> success
write, read -> hang

繰り返しになりますが、私はnoskloに select.select、単一スレッドからの任意の入力とパイプバッファリングを処理するための使用を示すコードを投稿するか、応答に賛成するように要求します。

結論:単一のスレッドからパイプの両端を操作しようとしないでください。それだけの価値はありません。これを正しく行う方法の優れた低レベルの例については、パイプラインを参照 してください。

于 2010-02-10T19:14:16.060 に答える
1

あなたは間違った問題を調べているのではないかと思います。確かに、アーロンが言うように、パイプラインの最初のプロデューサーとパイプラインの最後のコンシューマーの両方になろうとすると、デッドロック状態に陥りやすくなります。これは、communication()が解決する問題です。

stdinとstdoutは異なるサブプロセスオブジェクト上にあるため、communication()は正確には正しくありません。しかし、subprocess.pyの実装を見ると、Aaronが提案したとおりに機能していることがわかります。

読み取りと書き込みの両方を通信することがわかると、2回目の試行で、communicate()がp1の出力についてp2と競合することがわかります。

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)
# ...
p1.communicate('data\n')       # reads from p1.stdout, as does p2

私はwin32で実行しています。これは、明らかに異なるI / Oとバッファリングの特性を持っていますが、これは私にとってはうまくいきます。

p1 = Popen(["grep", "-v", "not"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)
t = threading.Thread(target=get_output, args=(p2,)) 
t.start()
p1.stdin.write('hello world\n' * 100000)
p1.stdin.close()
t.join()

ナイーブなスレッド化されていないp2.read()を使用すると、デッドロックが発生するように入力サイズを調整しました

また、ファイルにバッファリングしてみることもできます。

fd, _ = tempfile.mkstemp()
os.write(fd, 'hello world\r\n' * 100000)
os.lseek(fd, 0, os.SEEK_SET)
p1 = Popen(["grep", "-v", "not"], stdin=fd, stdout=PIPE)
p2 = Popen(["cut", "-c", "1-10"], stdin=p1.stdout, stdout=PIPE)
print p2.stdout.read()

これは、デッドロックなしでも機能します。

于 2009-10-23T00:49:36.160 に答える
0

SpooledTemporaryFileを使用するのはどうですか?これは問題を回避します(しかしおそらく解決しません):

http://docs.python.org/library/tempfile.html#tempfile.SpooledTemporaryFile

ファイルのように書き込むこともできますが、実際にはメモリブロックです。

それとも私は完全に誤解していますか...

于 2009-10-23T02:20:03.187 に答える
-1

これは、同じことを達成するためにos.forkと一緒にPopenを使用する例です。それを使用する代わりにclose_fds、適切な場所でパイプを閉じるだけです。を使用するよりもはるかに簡単でselect.select、システムパイプバッファを最大限に活用します。

from subprocess import Popen, PIPE
import os
import sys

p1 = Popen(["cat"], stdin=PIPE, stdout=PIPE)

pid = os.fork()

if pid: #parent
    p1.stdin.close()
    p2 = Popen(["cat"], stdin=p1.stdout, stdout=PIPE)
    data = p2.stdout.read()
    sys.stdout.write(data)
    p2.stdout.close()

else: #child
    data_to_write = 'hello world\n' * 100000
    p1.stdin.write(data_to_write)
    p1.stdin.close()
于 2010-02-11T15:44:39.133 に答える
-1

思ったよりずっと簡単です!

import sys
from subprocess import Popen, PIPE

# Pipe the command here. It will read from stdin.
#   So cat a file, to stdin, like (cat myfile | ./this.py),
#     or type on terminal and hit control+d when done, etc
#   No need to handle this yourself, that's why we have shell's!
p = Popen("grep -v not | cut -c 1-10", shell=True, stdout=PIPE)

nextData = None
while True:
    nextData = p.stdout.read()
    if nextData in (b'', ''):
        break
    sys.stdout.write ( nextData.decode('utf-8') )


p.wait()

このコードはPython3.6用に書かれており、Python2.7で動作します。

次のように使用します。

cat README.md  | python ./example.py

また

python example.py < README.md

「README.md」の内容をこのプログラムにパイプします。

しかし..この時点で、「cat」を直接使用して、必要に応じて出力をパイプ処理してみませんか?お気に入り:

cat filename | grep -v not | cut -c 1-10

コンソールに入力すると、同様に機能します。個人的には、出力をさらに処理する場合にのみコードオプションを使用します。そうしないと、シェルスクリプトの保守と保持が容易になります。

あなたはただ、あなたのために配管をするためにシェルを使用します。一方では、もう一方では。それが、彼女が実行、プロセスの管理、および入力と出力の単一幅のチェーンの管理に優れていることです。これをシェルの最高の非対話型機能と呼ぶ人もいます。

于 2017-07-19T03:02:28.500 に答える