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_outputhàm:
>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
check_outputchạ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 runhoặc Popenphầ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_outputchứ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 subprocessmô-đun. Để nắm bắt đầu ra của một chương trình, chuyển subprocess.PIPEcờ cho stdoutđối số từ khóa. Sau đó truy cập stdoutthuộ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 decodenó. 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.stdouttheo 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=Truenhư 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 runchứ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_outputchứ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_outputtương đương với việc thực thi runvới check=Truevà stdout=PIPEvà chỉ trả về stdoutthuộ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_outputcó 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=Truenhư mô tả trong các ghi chú bên dưới.
Nếu bạn cần chuyển từ stderrhoặc chuyển đầu vào cho quy trình, check_outputsẽ không hoàn thành nhiệm vụ. Xem các Popenví 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_outputcung cấp, bạn sẽ phải làm việc trực tiếp với Popencác đối tượng, đóng gói API cấp thấp cho các quy trình con.
Hàm Popentạ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.splitcó thể giúp phân tích chuỗi thành các danh sách được định dạng thích hợp. Popencá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, communicatehầ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, communicatecũ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, stderrvà stdintấ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 communicatelà 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_outputhoặc các Popennhà 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_outputtrả 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ó.