ここでの他の回答は、subprocess
ドキュメントにも記載されているセキュリティ上の警告を適切に説明しています。しかし、それに加えて、実行したいプログラムを開始するためにシェルを開始するオーバーヘッドは、多くの場合不要であり、実際にシェルの機能をまったく使用しない状況では間違いなくばかげています。さらに、シェルやシェルが提供するサービスに精通していない場合は特に、追加の隠された複雑さがあなたを怖がらせるはずです。
シェルとの相互作用が重要な場合は、Pythonスクリプトとシェルスクリプトの両方を理解するために、Pythonスクリプトの読者とメンテナー(将来の自分ではないかもしれません)が必要になります。Pythonのモットー「明示的なものは暗黙的なものより優れている」を覚えておいてください。Pythonコードが同等の(多くの場合非常に簡潔な)シェルスクリプトよりも多少複雑になる場合でも、シェルを削除して機能をネイティブのPython構成体に置き換える方がよいでしょう。外部プロセスで行われる作業を最小限に抑え、独自のコード内で可能な限り制御を維持することは、可視性が向上し、副作用のリスク(望まれるまたは望まれない)が軽減されるため、多くの場合良い考えです。
ワイルドカード拡張、変数補間、およびリダイレクトはすべて、ネイティブPython構成で置き換えるのが簡単です。パーツまたはすべてをPythonで合理的に書き換えることができない複雑なシェルパイプラインは、おそらくシェルの使用を検討できる状況の1つです。それでも、パフォーマンスとセキュリティへの影響を確実に理解する必要があります。
些細なケースでは、を避けるためにshell=True
、単に
subprocess.Popen("command -with -options 'like this' and\\ an\\ argument", shell=True)
と
subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])
最初の引数がに渡す文字列のリストであることexecvp()
、および文字列を引用符で囲んでシェルメタ文字をバックスラッシュでエスケープする必要がない(または有用である、または正しい)ことに注意してください。シェル変数を引用符で囲むタイミングも参照してください。
余談ですPopen
が、subprocess
パッケージ内のより単純なラッパーの1つが希望どおりに機能するかどうかを避けたいことがよくあります。最近十分なPythonを使用してsubprocess.run
いる場合は、おそらくを使用する必要があります。
- では
check=True
、実行したコマンドが失敗した場合、それは失敗します。
- これを使用
stdout=subprocess.PIPE
すると、コマンドの出力がキャプチャされます。
- ややあいまいですが、
universal_newlines=True
出力は適切なUnicode文字列にデコードされます(bytes
Python 3では、それ以外の場合はシステムエンコーディングに含まれます)。
そうでない場合、多くのタスクでcheck_output
、コマンドが成功したことを確認しながら、またはcheck_call
収集する出力がない場合に、コマンドから出力を取得する必要があります。
David Kornからの引用で締めくくります:「ポータブルシェルスクリプトよりもポータブルシェルを書く方が簡単です。」でも、subprocess.run('echo "$HOME"', shell=True)
Windowsに移植性がありません。
-l
に渡されます/bin/sh
(シェル)の代わりにls
プログラムのUnix上の場合shell=True
。shell=True
ほとんどの場合、リストの代わりに文字列引数を使用する必要があります。