2012-05-19 11 views
9

Es scheint, dass Shell mit = True in dem ersten Prozess einer Kette irgendwie die stdout von nachgelagerten Aufgaben fällt:Warum ist Shell = True essen mein Subprozess.Popen stdout?

p1 = Popen(['echo','hello'], stdout=PIPE) 
p2 = Popen('cat', stdin=p1.stdout, stdout=PIPE) 
p2.communicate() 
# outputs correctly ('hello\n', None) 

den ersten Prozess Verwendung Shell zu machen = True tötet den Ausgang irgendwie ...

p1 = Popen(['echo','hello'], stdout=PIPE, shell=True) 
p2 = Popen('cat', stdin=p1.stdout, stdout=PIPE) 
p2.communicate() 
# outputs incorrectly ('\n', None) 

shell = True auf den zweiten Prozess scheint keine Rolle zu spielen. Ist das erwartetes Verhalten?

Antwort

15

Wenn Sie shell=True übergeben, erwartet Popen ein einzelnes String-Argument, keine Liste. Also, wenn Sie dies tun:

p1 = Popen(['echo','hello'], stdout=PIPE, shell=True) 

Was passiert, ist dies:

execve("/bin/sh", ["/bin/sh", "-c", "echo", "hello"], ...) 

Das heißt, es nennt sh -c "echo" und hello wird effektiv ignoriert (technisch wird es ein Positions Argument der Shell). Also die Shell läuft echo, die \n druckt, weshalb Sie das in Ihrer Ausgabe sehen.

Wenn Sie shell=True verwenden möchten, müssen Sie dies tun:

p1 = Popen('echo hello', stdout=PIPE, shell=True) 
+3

Dank! Für die Nachwelt, hier ist die [docs] (http://docs.python.org/library/subprocess.html): Auf Unix, mit Shell = True: Wenn args eine Sequenz ist, gibt das erste Element die Befehlszeichenfolge, und alle zusätzlichen Elemente werden als zusätzliche Argumente für die Shell selbst behandelt. Das heißt, Popen macht das Äquivalent von: 'Popen (['/ bin/sh', '-c', args [0], args [1], ...])' –

+0

sehr schlecht dokumentiert, meiner bescheidenen Meinung nach – Davide