In den vorherigen Antworten wurde ein wichtiger Punkt übersehen. Ersetzen der Shell-Pipeline ist grundsätzlich korrekt, wie von geocar hervorgehoben. Es ist fast ausreichend für den Betrieb communicate
auf das letzte Element der Pipe.
Das verbleibende Problem ist die Übergabe der Eingangsdaten zur Pipeline. Bei mehreren Unterprozessen kann eine einfache communicate(input_data)
auf das letzte Element funktioniert nicht - es bleibt für immer hängen. Sie müssen eine Pipeline und ein Kind manuell wie folgt erstellen:
import os
import subprocess
input = """\
input data
more input
""" * 10
rd, wr = os.pipe()
if os.fork() != 0: # parent
os.close(wr)
else: # child
os.close(rd)
os.write(wr, input)
os.close(wr)
exit()
p_awk = subprocess.Popen(["awk", "{ print $2; }"],
stdin=rd,
stdout=subprocess.PIPE)
p_sort = subprocess.Popen(["sort"],
stdin=p_awk.stdout,
stdout=subprocess.PIPE)
p_awk.stdout.close()
out, err = p_sort.communicate()
print (out.rstrip())
Jetzt liefert das Kind die Eingabe über die Pipe, und das Elternteil ruft communicate() auf, was wie erwartet funktioniert. Mit diesem Ansatz können Sie beliebig lange Pipelines erstellen, ohne einen Teil der Arbeit an die Shell delegieren zu müssen. Leider ist die Teilprozessdokumentation wird dies nicht erwähnt.
Es gibt Möglichkeiten, den gleichen Effekt ohne Rohre zu erzielen:
from tempfile import TemporaryFile
tf = TemporaryFile()
tf.write(input)
tf.seek(0, 0)
Verwenden Sie nun stdin=tf
para p_awk
. Es ist eine Frage des Geschmacks, was Sie bevorzugen.
Die obige Lösung ist immer noch nicht 100%ig äquivalent zu Bash-Pipelines, da die Signalverarbeitung anders ist. Sie können dies sehen, wenn Sie ein weiteres Pipe-Element hinzufügen, das die Ausgabe von sort
z.B. head -n 10
. Mit dem obigen Code, sort
gibt eine Fehlermeldung "Broken pipe" an stderr
. Sie werden diese Meldung nicht sehen, wenn Sie dieselbe Pipeline in der Shell ausführen. (Das ist allerdings der einzige Unterschied, das Ergebnis in stdout
ist derselbe). Der Grund dafür scheint zu sein, dass Pythons Popen
setzt SIG_IGN
para SIGPIPE
, während die Schale sie bei SIG_DFL
et sort
Die Signalverarbeitung ist in diesen beiden Fällen unterschiedlich.