2012-05-19 21 views
9

Dường như sử dụng vỏ = True trong quá trình đầu tiên của một chuỗi bằng cách nào đó đánh rơi stdout từ nhiệm vụ hạ lưu:Tại sao shell = True ăn subprocess của tôi.Popen stdout?

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

Làm vỏ quá trình sử dụng đầu tiên = True giết đầu ra bằng cách nào đó ...

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

shell = Đúng trên quy trình thứ hai dường như không quan trọng. Đây có phải là hành vi mong đợi không?

Trả lời

15

Khi bạn vượt qua shell=True, Popen dự kiến ​​một đối số chuỗi đơn, không phải danh sách. Vì vậy, khi bạn làm điều này:

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

gì sẽ xảy ra đây là:

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

Nghĩa là, nó gọi sh -c "echo", và hello bị bỏ qua một cách hiệu quả (về mặt kỹ thuật nó trở thành một cuộc tranh luận về vị trí để vỏ). Vì vậy, vỏ chạy echo, in \n, đó là lý do tại sao bạn thấy rằng trong đầu ra của bạn.

Nếu bạn sử dụng shell=True, bạn cần phải làm điều này:

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

Cảm ơn! Đối với hậu thế, đây là [tài liệu] (http://docs.python.org/library/subprocess.html): Trên Unix, với shell = True: Nếu arg là một chuỗi, mục đầu tiên chỉ định chuỗi lệnh, và bất kỳ mục bổ sung nào sẽ được coi là đối số bổ sung cho chính shell đó. Tức là, Popen thực hiện tương đương với: 'Popen (['/ bin/sh', '-c', args [0], args [1], ...])' –

+0

được ghi nhận rất kém, IMHO – Davide

Các vấn đề liên quan