2012-05-19 4 views
9

кажется, что с помощью оболочки = True в первом процессе цепочки как-то роняет стандартный вывод из последующих задач:Почему shell = True есть мой subprocess.Popen stdout?

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

Создание первого использования процесса оболочки = True убивает выход как-то ...

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

shell = True на втором процессе, похоже, не имеет значения. Это ожидаемое поведение?

ответ

15

Когда вы проходите shell=True, Popen ожидает один строковый аргумент, а не список. Так что, когда вы это делаете:

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

Что происходит:

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

То есть, он вызывает sh -c "echo" и hello эффективно игнорируются (технически это становится позиционным аргументом оболочки). Таким образом, оболочка запускает echo, который печатает \n, поэтому вы видите это в своем выходе.

Если вы используете shell=True, что вам нужно сделать это:

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

Спасибо! Для потомков вот [docs] (http://docs.python.org/library/subprocess.html): В Unix с оболочкой = True: если args - это последовательность, первый элемент указывает строку команды, и любые дополнительные элементы будут рассматриваться как дополнительные аргументы самой оболочки. То есть, Popen делает эквивалент: 'Popen (['/ bin/sh', '-c', args [0], args [1], ...])' –

+0

очень плохо документирован, ИМХО – Davide

Смежные вопросы