Các câu trả lời khác ở đây giải thích thỏa đáng các cảnh báo an ninh cũng được đề cập trong subprocess
tài liệu. Nhưng ngoài ra, chi phí khởi động chương trình để bắt đầu chương trình bạn muốn chạy thường không cần thiết và chắc chắn là ngớ ngẩn đối với các tình huống mà bạn không thực sự sử dụng bất kỳ chức năng nào của trình bao. Hơn nữa, sự phức tạp ẩn thêm sẽ làm bạn sợ, đặc biệt là nếu bạn không quen thuộc với trình bao hoặc các dịch vụ mà nó cung cấp.
Trong đó các tương tác với shell là không cần thiết, bây giờ bạn yêu cầu người đọc và người duy trì tập lệnh Python (có thể là hoặc không phải là bản thân tương lai của bạn) để hiểu cả Python và shell script. Ghi nhớ phương châm Python "rõ ràng là tốt hơn ngầm định"; ngay cả khi mã Python sẽ phức tạp hơn một chút so với tập lệnh shell tương đương (và thường rất ngắn gọn), bạn có thể nên loại bỏ shell và thay thế chức năng bằng các cấu trúc Python nguyên gốc. Giảm thiểu công việc được thực hiện trong một quy trình bên ngoài và giữ quyền kiểm soát trong mã của bạn càng nhiều càng tốt thường là một ý tưởng tốt đơn giản vì nó giúp cải thiện khả năng hiển thị và giảm rủi ro của các tác dụng phụ mong muốn hoặc không mong muốn.
Mở rộng ký tự đại diện, nội suy biến đổi và chuyển hướng đều đơn giản để thay thế bằng các cấu trúc Python nguyên gốc. Một đường ống vỏ phức tạp nơi các bộ phận hoặc tất cả không thể được viết lại một cách hợp lý trong Python sẽ là một tình huống mà có lẽ bạn có thể cân nhắc sử dụng trình bao. Bạn vẫn nên đảm bảo rằng bạn hiểu hiệu suất và ý nghĩa bảo mật.
Trong trường hợp tầm thường, để tránh shell=True
, chỉ cần thay thế
subprocess.Popen("command -with -options 'like this' and\\ an\\ argument", shell=True)
với
subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])
Lưu ý cách đối số đầu tiên là một danh sách các chuỗi cần chuyển đến execvp()
và cách trích dẫn các chuỗi siêu ký tự shell thoát dấu gạch chéo thường không cần thiết (hoặc hữu ích hoặc chính xác). Có lẽ cũng thấy Khi nào bọc dấu ngoặc kép quanh một biến shell?
Như một bên, bạn rất muốn tránh Popen
nếu một trong những trình bao bọc đơn giản hơn trong subprocess
gói làm những gì bạn muốn. Nếu bạn có một Python đủ gần đây, có lẽ bạn nên sử dụng subprocess.run
.
- Với
check=True
nó sẽ thất bại nếu lệnh bạn chạy thất bại.
- Với
stdout=subprocess.PIPE
nó sẽ nắm bắt đầu ra của lệnh.
- Hơi khó hiểu, với
universal_newlines=True
nó sẽ giải mã đầu ra thành một chuỗi Unicode thích hợp (nó chỉ bytes
nằm trong mã hóa hệ thống, trên Python 3).
Nếu không, đối với nhiều tác vụ, bạn muốn check_output
lấy đầu ra từ một lệnh, trong khi kiểm tra xem nó có thành công hay khôngcheck_call
chưa có đầu ra để thu thập.
Tôi sẽ kết thúc bằng một câu trích dẫn của David Korn: "Viết shell dễ dàng hơn so với kịch bản shell di động." Thậm chí subprocess.run('echo "$HOME"', shell=True)
không thể mang theo Windows.
-l
được truyền cho/bin/sh
(shell) thay vìls
chương trình trên Unix nếushell=True
. Đối số chuỗi nên được sử dụng vớishell=True
trong hầu hết các trường hợp thay vì danh sách.