2017-06-23 6 views
3

最近、サブプロセスがos.systemよりはるかに優れていると言っているスタックオーバーフローに関する記事がいくつか出てきましたが、正確な利点を見つけるのは難しいです。os.system上のサブプロセスのメリット

私はに実行したことのいくつかの例:「サブプロセスモジュールは、新しいプロセスを生成し、その結果を取得するためのより強力な機能を提供し、そのモジュールを使用すると、この機能を使用することが好ましい。」 https://docs.python.org/3/library/os.html#os.system

どのようにしてより強力なアイデアはありませんが、私はサブプロセスを使用する方が多くの点でより簡単だと思いますが、実際にはもっと強力です。

別の例は次のとおりです。

https://stackoverflow.com/a/89243/3339122

サブプロセスVSシステムの利点は、それが「本当の」ステータスコード、標準エラー出力(あなたが標準出力を得ることができ、より柔軟であるということです、エラー処理の改善など)。

この投稿は2600+票を持っています。エラー処理や実際の状態コードの意味合いが何であるかについては、これ以上調べることができませんでした。その記事に

トップのコメントは以下のとおりです。あなたも迅速/汚い/一回os.system使用したい理由

は見ることができません。サブプロセスはずっと良いようです。

繰り返しますが、私はそれはいくつかの物事が少し容易になります理解が、私はほとんど、たとえば理由を理解することはできません。

subprocess.call("netsh interface set interface \"Wi-Fi\" enable", shell=True) 

os.system("netsh interface set interface \"Wi-Fi\" enabled") 

よりも良くあり、誰もがいくつかの理由にそれを説明することができますはるかに良いですか?

+2

あなたは 'subprocess.call'の使い方が間違っているので、明らかにAPIを調べていません。 APIドキュメントを読んで、高度なユースケースの例を見てください。 –

+1

@JonathonReinhartちょうど記録のために。実際には、shell = Trueの有無にかかわらずうまく動作します。私は確かにドキュメントを読んでいます。なぜ私のコードが動作しているのか、それともなぜ動作していないのかは疑問ではありません。私はあなたが望む場合は、例を更新することができます、質問はまだそれらの違いです。あなたが結論にジャンプしたり、他の研究をする前に、https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocessを参照してください。私はコードがどのように動作するのか知っていますが、なぜ私が何か他のものを使っているのか分かりません。 – Lain

+0

これは、ウィンドウの実装のいくつかの奇妙なアーティファクトでなければなりません。 1つのOSで "動作する"という意味では、それが正しく使用されているわけではありません。 –

答えて

5

まず、あなたは仲買人を切り出しています。 subprocess.callは、デフォルトでは、コマンドを調べるシェルを生成するのを避け、要求されたプロセスを直接生成します。これは、問題の効率面の他に、デフォルトのシェル動作を多く制御することができず、実際にはエスケープに関して実際にあなたに反対するため重要です。単一の文字列を渡し、どちらかshellTrue(下記参照)でなければならない場合

subprocess.call("netsh interface set interface \"Wi-Fi\" enable") 

ため、または他の文字列は、単純に名前を付ける必要があります。特に

、一般的にこれを行うことはありません引数を指定せずに実行されるプログラム。

代わりに、あなたがやる:ここでは、すべてのエスケープ悪夢がなくなっている

subprocess.call(["netsh", "interface", "set", "interface", "Wi-Fi", "enable"]) 

注意してください。 subprocessは、エスケープ処理(OSがWindowsなどの単一の文字列として引数を必要とする場合)を処理したり、分離した引数を関連するシステムコール(UNIXではexecvp)に直接渡します。

(私を信じて、特に自分のものをいじり途中でシェルと、(cmdはPOSIX shと同じようにエスケープしていない)、特にクロスプラットフォームな方法で、自分自身をエスケープを処理することでこれを比較cmd /kを呼び出すときにあなたのコマンドに100%の安全なエスケープを提供することが大変な混乱であるかどうかを知りたくはありません。

また、subprocessをシェルなしで使用している場合は、が正しいリターンコードになると確信しています。プロセスの起動に失敗した場合、Pythonの例外が発生します。リターンコードを取得すると、実際には起動したプログラムのリターンコードになります。 os.systemを使用すると、取得したリターンコードが起動したコマンド(シェルが起動すると通常はデフォルトの動作)か、シェルから何らかのエラーが発生したかどうかを知る方法がありませんそれを起動する)。


引数の分割/エスケープとリターンコード以外にも、起動したプロセスをより詳細に制御できます。 機能よりも最も基本的なユーティリティ機能であるsubprocess.callであっても、stdin,stdoutおよびstderrをリダイレクトすることができ、おそらく起動プロセスと通信します。 check_callは似ており、失敗の終了コードを無視するリスクを回避します。 check_outputは、check_call +の共通の使用例+すべてのプログラム出力を文字列変数に取り込みます。

あなたが(ちょうどos.systemとブロックしている)call &友人を乗り越えるたら、道より強力な機能があります - 特に、Popenオブジェクトは、あなたは非同期で起動したプロセスで動作することができます。あなたはリダイレクトされたストリームを通してそれと話をしたり、他のものをやっている間に随時実行されているかどうかを確認したり、完了するのを待ったり、シグナルを送信したり、それを殺したりすることができますシェルを介してデフォルトのstdin/stdout/stderrを使用して同期プロセスを開始し、完了するのを待ってから "os.systemが提供します。

だから、

subprocessで、それを総括する:

  • も、最も基本的なレベル(call &友人)で、あなた:Pythonのリストを渡すことで問題を脱出
    • 回避議論の
    • コマンドラインでシェルが邪魔にならないようにします。
    • あなたが起動したプロセスの例外または真の終了コードがあります。プログラム/シェル終了コードに関する混乱はありません。
    • は標準出力をキャプチャする可能性があり、一般に標準ストリームをリダイレクトします。
  • あなたがPopenを使用します。
    • あなたが同期インタフェースに制限されていませんが、あなたが実際にサブプロセスの実行中に他のものを行うことができます。
    • サブプロセスを制御できます(実行中かどうかを確認したり、通信したり、終了したりできます)。

subprocessを行うことができる方法を超えるos.systemをすることを考える - より安全な、(あなたがそれを必要とする場合)、より柔軟な方法で - 代わりにsystemを使用するだけの理由がありません。

3

あり、多くの理由がありますが、主な理由は、ドキュメンテーション文字列に直接言及されています

>>> os.system.__doc__ 
'Execute the command in a subshell.' 

あなたがサブプロセスを必要とするほぼすべてのケースでは、サブシェルを起動するは望ましくありません。これは不要で無駄であり、複雑なレイヤを追加し、いくつかの新しい脆弱性や障害モードを導入します。 subprocessモジュールを使用すると、仲介人が削減されます。

+0

ありがとうございます。より正確なエラー処理、実際のステータスコード、または私の記事の人々の話で言及した他のものには正確に答えていません。あなたの投稿でも同じことをしています。新しい脆弱性/障害モードが何であるかは不明ですし、サブシェルを生成するのが望ましいかどうかは不明です。これからの小さな無駄を集めて、それほど多くのサポートがすべてであるとは想像できません。 – Lain

+0

シェルを使用すると、オペレーティングシステムと対話できます。 Pythonはまた、オペレーティングシステムと対話するために必要なすべての機能を備えています。 Pythonにシェルにオペレーティングシステムとの対話を依頼するのはなぜですか?余分な複雑さは、パイプやエスケープのようなものをシェル言語に翻訳する必要があるためです。脆弱性について知るには、[shell injection](https://en.wikipedia.org/wiki/Code_injection#Shell_injection)を検索してください。 – wim

関連する問題