Jawaban lain di sini cukup menjelaskan peringatan keamanan yang juga disebutkan dalam subprocess
dokumentasi. Tetapi selain itu, overhead memulai shell untuk memulai program yang ingin Anda jalankan seringkali tidak perlu dan tentu saja konyol untuk situasi di mana Anda tidak benar-benar menggunakan fungsionalitas shell. Selain itu, kompleksitas tersembunyi tambahan akan membuat Anda takut, terutama jika Anda tidak terlalu mengenal shell atau layanan yang disediakannya.
Di mana interaksi dengan shell adalah non-trivial, Anda sekarang memerlukan pembaca dan pengelola skrip Python (yang mungkin atau mungkin bukan diri Anda di masa depan) untuk memahami skrip Python dan shell. Ingat moto Python "eksplisit lebih baik daripada implisit"; bahkan ketika kode Python akan menjadi sedikit lebih kompleks daripada skrip shell yang setara (dan seringkali sangat singkat), Anda mungkin lebih baik menghapus shell dan mengganti fungsi dengan konstruksi Python asli. Meminimalkan pekerjaan yang dilakukan dalam proses eksternal dan menjaga kontrol dalam kode Anda sendiri sejauh mungkin seringkali merupakan ide yang baik hanya karena meningkatkan visibilitas dan mengurangi risiko efek samping yang diinginkan atau tidak diinginkan.
Ekspansi wildcard, interpolasi variabel, dan pengalihan semuanya mudah untuk diganti dengan konstruksi Python asli. Sebuah pipeline shell yang kompleks di mana sebagian atau semua tidak dapat ditulis ulang secara wajar dengan Python akan menjadi satu situasi di mana mungkin Anda bisa mempertimbangkan untuk menggunakan shell. Anda harus tetap memastikan bahwa Anda memahami implikasi kinerja dan keamanan.
Dalam kasus sepele, untuk menghindari shell=True
, cukup ganti
subprocess.Popen("command -with -options 'like this' and\\ an\\ argument", shell=True)
dengan
subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])
Perhatikan bagaimana argumen pertama adalah daftar string untuk diteruskan execvp()
, dan bagaimana mengutip string dan karakter karakter shell backslash-escape umumnya tidak diperlukan (atau berguna, atau benar). Mungkin lihat juga Kapan membungkus tanda kutip di sekitar variabel shell?
Sebagai tambahan, Anda sangat sering ingin menghindari Popen
jika salah satu pembungkus sederhana dalam subprocess
paket melakukan apa yang Anda inginkan. Jika Anda memiliki Python yang cukup baru, Anda mungkin harus menggunakan subprocess.run
.
- Dengan
check=True
itu akan gagal jika perintah yang Anda jalankan gagal.
- Dengan
stdout=subprocess.PIPE
itu akan menangkap output perintah.
- Agak tidak jelas, dengan
universal_newlines=True
itu akan mendekode output menjadi string Unicode yang tepat (itu hanya bytes
dalam sistem pengkodean sebaliknya, pada Python 3).
Jika tidak, untuk banyak tugas, Anda ingin check_output
mendapatkan output dari perintah, sambil memeriksa apakah berhasil, atau check_call
jika tidak ada output untuk dikumpulkan.
Saya akan menutup dengan kutipan dari David Korn: "Lebih mudah untuk menulis shell portabel daripada skrip shell portabel." Bahkan subprocess.run('echo "$HOME"', shell=True)
tidak portabel untuk Windows.
-l
dilewatkan ke/bin/sh
(shell) alih-alihls
program di Unix jikashell=True
. Argumen string harus digunakan denganshell=True
dalam banyak kasus, bukan daftar.