2012-05-19 7 views
9

Sembra che utilizza shell = True nel primo processo di una catena cade in qualche modo lo stdout da compiti a valle:Perché shell = True mangia il mio subprocess.Popen stdout?

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

Portando il guscio primo processo utilizzare = True uccide l'uscita qualche modo ...

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

shell = True sul secondo processo non sembra avere importanza. È questo comportamento previsto?

risposta

15

Quando si passa shell=True, Popen si aspetta un singolo argomento di stringa, non un elenco. Quindi, quando si esegue questa operazione:

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

Quello che succede è questo:

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

Cioè, chiama sh -c "echo", e hello viene effettivamente ignorata (tecnicamente diventa un argomento posizionale al guscio). Quindi la shell gira echo, che stampa \n, che è il motivo per cui lo vedi nel tuo output.

Se si utilizza shell=True, è necessario fare questo:

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

Grazie! Per i posteri, ecco i [documenti] (http://docs.python.org/library/subprocess.html): Su Unix, con shell = True: Se args è una sequenza, il primo elemento specifica la stringa di comando, e tutti gli altri elementi saranno trattati come argomenti aggiuntivi alla shell stessa. Vale a dire, Popen fa l'equivalente di: 'Popen (['/ bin/sh', '-c', args [0], args [1], ...])' –

+0

molto scarsamente documentato, A parer mio – Davide