Câu trả lời cho câu hỏi này phụ thuộc vào phiên bản Python bạn đang sử dụng. Cách tiếp cận đơn giản nhất là sử dụng subprocess.check_output
hàm:
>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
check_output
chạy một chương trình duy nhất chỉ lấy các đối số làm đầu vào. 1 Nó trả về kết quả chính xác như được in stdout
. Nếu bạn cần viết đầu vào stdin
, bỏ qua phần trước run
hoặc Popen
phần. Nếu bạn muốn thực thi các lệnh shell phức tạp, hãy xem ghi chú shell=True
ở cuối câu trả lời này.
Các check_output
chức năng hoạt động trên hầu hết các phiên bản của Python vẫn sử dụng rộng rãi (2.7+). 2 Nhưng đối với các phiên bản gần đây hơn, nó không còn là phương pháp được đề xuất.
Các phiên bản hiện đại của Python (3,5 trở lên): run
Nếu bạn đang sử dụng Python 3.5 trở lên và không cần khả năng tương thích ngược , chức năng mớirun
được khuyến nghị. Nó cung cấp một API cấp cao, rất chung cho subprocess
mô-đun. Để nắm bắt đầu ra của một chương trình, chuyển subprocess.PIPE
cờ cho stdout
đối số từ khóa. Sau đó truy cập stdout
thuộc tính của CompletedProcess
đối tượng trả về :
>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Giá trị trả về là một bytes
đối tượng, vì vậy nếu bạn muốn có một chuỗi thích hợp, bạn sẽ cần đến decode
nó. Giả sử quy trình được gọi trả về chuỗi được mã hóa UTF-8:
>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Tất cả điều này có thể được nén thành một lớp lót:
>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Nếu bạn muốn chuyển đầu vào cho tiến trình stdin
, hãy chuyển một bytes
đối tượng cho input
đối số từ khóa:
>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'
Bạn có thể chụp lỗi bằng cách chuyển stderr=subprocess.PIPE
(chụp đến result.stderr
) hoặc stderr=subprocess.STDOUT
(chụp result.stdout
theo cùng với đầu ra thông thường). Khi bảo mật không phải là vấn đề đáng lo ngại, bạn cũng có thể chạy các lệnh shell phức tạp hơn bằng cách chuyển shell=True
như mô tả trong các ghi chú bên dưới.
Điều này chỉ thêm một chút phức tạp, so với cách làm cũ. Nhưng tôi nghĩ rằng nó đáng để trả tiền: bây giờ bạn có thể làm hầu hết mọi thứ bạn cần làm với run
chức năng một mình.
Các phiên bản cũ hơn của Python (2.7-3.4): check_output
Nếu bạn đang sử dụng phiên bản cũ hơn của Python hoặc cần khả năng tương thích ngược khiêm tốn, có lẽ bạn có thể sử dụng check_output
chức năng như được mô tả ngắn gọn ở trên. Nó đã có sẵn từ Python 2.7.
subprocess.check_output(*popenargs, **kwargs)
Nó nhận các đối số tương tự như Popen
(xem bên dưới) và trả về một chuỗi chứa đầu ra của chương trình. Phần đầu của câu trả lời này có một ví dụ sử dụng chi tiết hơn. Trong Python 3.5 trở lên, check_output
tương đương với việc thực thi run
với check=True
và stdout=PIPE
và chỉ trả về stdout
thuộc tính.
Bạn có thể vượt qua stderr=subprocess.STDOUT
để đảm bảo rằng các thông báo lỗi được bao gồm trong đầu ra được trả về - nhưng trong một số phiên bản Python chuyển stderr=subprocess.PIPE
đến check_output
có thể gây ra bế tắc . Khi bảo mật không phải là vấn đề đáng lo ngại, bạn cũng có thể chạy các lệnh shell phức tạp hơn bằng cách chuyển shell=True
như mô tả trong các ghi chú bên dưới.
Nếu bạn cần chuyển từ stderr
hoặc chuyển đầu vào cho quy trình, check_output
sẽ không hoàn thành nhiệm vụ. Xem các Popen
ví dụ dưới đây trong trường hợp đó.
Các ứng dụng phức tạp và các phiên bản kế thừa của Python (2.6 trở xuống): Popen
Nếu bạn cần khả năng tương thích ngược sâu hoặc nếu bạn cần chức năng phức tạp hơn check_output
cung cấp, bạn sẽ phải làm việc trực tiếp với Popen
các đối tượng, đóng gói API cấp thấp cho các quy trình con.
Hàm Popen
tạo chấp nhận một lệnh đơn không có đối số hoặc danh sách chứa lệnh là mục đầu tiên của nó, theo sau là bất kỳ số lượng đối số nào, mỗi đối số là một mục riêng biệt trong danh sách. shlex.split
có thể giúp phân tích chuỗi thành các danh sách được định dạng thích hợp. Popen
các đối tượng cũng chấp nhận một loạt các đối số khác nhau để quản lý IO quá trình và cấu hình mức thấp.
Để gửi đầu vào và đầu ra chụp, communicate
hầu như luôn luôn là phương thức ưa thích. Như trong:
output = subprocess.Popen(["mycmd", "myarg"],
stdout=subprocess.PIPE).communicate()[0]
Hoặc là
>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE,
... stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo
Nếu bạn đặt stdin=PIPE
, communicate
cũng cho phép bạn chuyển dữ liệu tới quy trình thông qua stdin
:
>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
... stderr=subprocess.PIPE,
... stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo
Lưu ý câu trả lời Aaron Hall , mà chỉ ra rằng trên một số hệ thống, bạn có thể cần phải thiết lập stdout
, stderr
và stdin
tất cả mọi người PIPE
(hoặc DEVNULL
) để có được communicate
để làm việc ở tất cả.
Trong một số trường hợp hiếm hoi, bạn có thể cần chụp đầu ra thời gian thực phức tạp. Câu trả lời của Vartec cho thấy một con đường phía trước, nhưng các phương pháp khác hơn communicate
là dễ bị bế tắc nếu không được sử dụng cẩn thận.
Như với tất cả các chức năng trên, khi bảo mật không phải là vấn đề đáng lo ngại, bạn có thể chạy các lệnh shell phức tạp hơn bằng cách chuyển shell=True
.
Ghi chú
1. Chạy lệnh shell: shell=True
đối số
Thông thường, mỗi cuộc gọi đến run
, check_output
hoặc các Popen
nhà xây dựng thực hiện một chương trình đơn lẻ . Điều đó có nghĩa là không có đường ống kiểu bash ưa thích. Nếu bạn muốn chạy các lệnh shell phức tạp, bạn có thể vượt qua shell=True
, cả ba chức năng đều hỗ trợ.
Tuy nhiên, làm như vậy làm tăng mối quan tâm an ninh . Nếu bạn đang làm bất cứ điều gì ngoài kịch bản nhẹ, bạn nên gọi riêng từng quy trình và chuyển đầu ra từ mỗi quy trình sang đầu vào tiếp theo, thông qua
run(cmd, [stdout=etc...], input=other_output)
Hoặc là
Popen(cmd, [stdout=etc...]).communicate(other_output)
Sự cám dỗ để kết nối trực tiếp các đường ống là mạnh mẽ; chống lại nó. Nếu không, bạn có thể sẽ thấy bế tắc hoặc phải làm những việc như thế này .
2. Cân nhắc về Unicode
check_output
trả về một chuỗi trong Python 2, nhưng một bytes
đối tượng trong Python 3. Thật đáng để dành một chút thời gian để tìm hiểu về unicode nếu bạn chưa có.