2016-03-23 26 views
6

script python của tôi (python 3.4.3) gọi một kịch bản bash qua tiến trình con:Python subprocess .check_call vs .check_output

import subprocess as sp 
res = sp.check_output("bashscript", shell=True) 

Các bashscript chứa các dòng sau:

ssh -MNf somehost 

mà mở một kết nối chính được chia sẻ với một số máy chủ từ xa để cho phép một số hoạt động tiếp theo.

Khi thực thi tập lệnh python, nó sẽ nhắc nhập mật khẩu cho dòng ssh nhưng sau đó nó chặn sau khi nhập mật khẩu và không bao giờ trả về. Khi tôi ctrl-C để chấm dứt tập lệnh, tôi thấy rằng kết nối đã được thiết lập đúng cách (vì vậy dòng ssh đã được thực thi thành công).

Tôi không gặp sự cố chặn này khi sử dụng check_call thay vì check_output, nhưng check_call không truy xuất giá trị xuất chuẩn. Tôi muốn hiểu chính xác những gì đang gây ra hành vi chặn cho check_output, có thể liên quan đến một số sự tinh tế với ssh -MNf.

Trả lời

19

check_call() trả về ngay sau khi thoát khỏi quy trình /bin/sh mà không cần chờ quá trình hậu duệ.

check_output() đợi cho đến khi tất cả đầu ra được đọc. Nếu ssh kế thừa đường ống thì check_output() sẽ đợi cho đến khi nó thoát ra (cho đến khi nó đóng các đầu ống kế thừa của nó).

check_call() mã ví dụ:

#!/usr/bin/env python 
import subprocess 
import sys 
import time 

start = time.time() 
cmd = sys.executable + " -c 'import time; time.sleep(2)' &" 
subprocess.check_call(cmd, shell=True) 
assert (time.time() - start) < 1 

Sản lượng không đọc; check_call() trả về ngay lập tức mà không cần chờ quá trình python nền của cháu.

check_call() chỉ là Popen().wait(). Popen() bắt đầu quá trình bên ngoài và trả về ngay lập tức mà không phải đợi để thoát. .wait() thu thập trạng thái thoát cho quy trình - nó không chờ các quy trình (cháu) khác.

Nếu đầu ra được đọc (nó bị đổi hướng và quá trình cháu python thừa hưởng các đường ống stdout):

start = time.time() 
subprocess.check_output(cmd, shell=True) 
assert (time.time() - start) > 2 

sau đó nó chờ đợi cho đến khi quá trình python nền mà thừa hưởng lối ống.

check_output() gọi Popen().communicate() để nhận kết quả. .communicate() gọi .wait() nội bộ tức là, check_output() cũng đợi vỏ xuất cảnh và check_output() chờ EOF.

Nếu cháu không kế thừa các đường ống sau đó check_output() không đợi cho nó:

start = time.time() 
cmd = sys.executable + " -c 'import time; time.sleep(2)' >/dev/null &" 
subprocess.check_output(cmd, shell=True) 
assert (time.time() - start) < 1 

sản lượng Cháu được chuyển đến /dev/null tức là, nó không kế thừa ống của cha mẹ và do đó có thể thoát khỏi check_output() mà không cần chờ đợi.

Lưu ý: & ở cuối đặt quá trình python cháu vào nền. Nó sẽ không hoạt động trên Windows nơi mặc định là shell=True bắt đầu cmd.exe.

+0

Giải thích tuyệt vời. –

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