Pythonから外部コマンドを呼び出す


4886

Pythonスクリプト内から外部コマンドを呼び出す方法(UnixシェルまたはWindowsコマンドプロンプトで入力した場合と同様)

回答:


4696

標準ライブラリのサブプロセスモジュールを見てください。

import subprocess
subprocess.run(["ls", "-l"])

利点subprocess対は、systemそれは(あなたが得ることができ、より柔軟であることであるstdoutstderr「本物の」ステータスコード、より良いエラー処理、等...)。

公式ドキュメントは推奨していますsubprocess代替の上にモジュールをos.system()

このsubprocessモジュールは、新しいプロセスを生成してその結果を取得するためのより強力な機能を提供します。この関数を使用するよりも、そのモジュールを使用することをお勧めします[ os.system()]。

サブプロセスモジュールと交換古い関数内のセクションsubprocessのドキュメントは、いくつかの有用なレシピを有することができます。

3.5より前のバージョンのPythonでは、次を使用しますcall

import subprocess
subprocess.call(["ls", "-l"])

変数置換を使用する方法はありますか?IE私はをecho $PATH使用して実行しようとしましたcall(["echo", "$PATH"])$PATH、置換を行う代わりにリテラル文字列をエコーし​​ました。PATH環境変数を取得できることはわかっていますが、コマンドをbashで実行したかのように正確に動作させる簡単な方法があるかどうか疑問に思っています。
Kevin Wheeler

@KevinWheelerこれを機能させるために使用する必要がありますshell=True
SethMMorton

39
@KevinWheeler shell=TruePythonにはos.path.expandvarsが付属しているため、使用しないでください。あなたのケースでは次のように記述することができますos.path.expandvars("$PATH")。@SethMMortonはコメントを再検討してください-> shell = Trueを使用しないのはなぜですか
Murmel

通話をブロックしますか?つまり、forループで複数のコマンドを実行したい場合、pythonスクリプトをブロックせずにそれを行うにはどうすればよいですか?たくさん実行したいコマンドの出力は気にしません。
チャーリーパーカー

5
パラメータを使用してコマンドからリスト作成するsubprocess場合はshell=False、when で使用できるリストを使用shlex.splitして、これを行う簡単な方法としてdocs.python.org/2/library/shlex.html#shlex.split
ダニエルF

2985

外部プログラムを呼び出す方法の概要と、それぞれの長所と短所を次に示します。

  1. os.system("some_command with args")コマンドと引数をシステムのシェルに渡します。この方法で実際に一度に複数のコマンドを実行し、パイプと入出力リダイレクトを設定できるので、これは素晴らしいことです。例えば:

    os.system("some_command < input_file | another_command > output_file")  

ただし、これは便利ですが、スペースなどのシェル文字のエスケープを手動で処理する必要があります。一方、これにより、単にシェルコマンドであり、実際には外部プログラムではないコマンドを実行することもできます。ドキュメントを参照してください。

  1. stream = os.popen("some_command with args")と同じことを行いos.systemますが、そのプロセスの標準入出力にアクセスするために使用できるファイルのようなオブジェクトを提供します。popenには他にも3つのバリエーションがあり、すべてがわずかに異なる方法でI / Oを処理します。すべてを文字列として渡すと、コマンドはシェルに渡されます。それらをリストとして渡すと、何かをエスケープすることを心配する必要はありません。ドキュメントを参照してください。

  2. モジュールのPopenクラスsubprocess。これはの代替品として意図されてos.popenいますが、非常に包括的であるために少し複雑になるという欠点があります。たとえば、次のようにします。

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()

    の代わりに:

    print os.popen("echo Hello World").read()

    ただし、4つの異なるpopen関数ではなく、1つの統合クラスにすべてのオプションを含めると便利です。ドキュメントを参照してください。

  3. モジュールcallからの関数subprocess。これは基本的にPopenクラスと同じで、すべて同じ引数を取りますが、コマンドが完了して戻りコードが返されるまで待つだけです。例えば:

    return_code = subprocess.call("echo Hello World", shell=True)  

    ドキュメントを参照してください。

  4. Python 3.5以降を使用している場合は、新しいsubprocess.run関数を使用できます。これは、上記とよく似ていますが、さらに柔軟性が高くCompletedProcess、コマンドの実行が完了するとオブジェクトを返します。

  5. osモジュールには、Cプログラムにあるすべてのfork / exec / spawn関数もありますが、直接使用することはお勧めしません。

subprocessモジュールは、おそらくあなたが使用しているものでなければなりません。

最後に、シェルが文字列として実行する最後のコマンドを渡すすべてのメソッドで、エスケープする必要があることに注意してください。渡す文字列の一部が完全に信頼できない場合、セキュリティに深刻な影響があります。たとえば、ユーザーが文字列の一部/任意の部分を入力している場合。不明な場合は、これらのメソッドを定数でのみ使用してください。影響のヒントを与えるには、次のコードを検討してください。

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

そして、ユーザーが「私のママは私を愛していなかった&& rm -rf /」と入力すると、ファイルシステム全体が消去される可能性があります。


22
いい答え/説明。この回答は、この記事で説明されているPythonのモットーをどのように正当化するのですか? fastcompany.com/3026446/… 「文体的には、PerlとPythonは異なる哲学を持っています。Perlの最もよく知られているモットーは、「それを行う方法は1つではありません」です。Pythonは、それを行う1つの明白な方法を持つように設計されています」反対に!Perlでは、コマンドを実行する方法が2つだけわかっていますopen
Jean

12
Python 3.5以降を使用してsubprocess.run()いる場合は、を使用します。docs.python.org/3.5/library/subprocess.html#subprocess.run
フェニックス

4
一般に知っておく必要があるのは、子プロセスのSTDOUTとSTDERRで何が行われるかです。これらが無視されると、いくつかの(ごく一般的な)条件下で、最終的に子プロセスがシステムコールを発行してSTDOUTに書き込みます(STDERRも?)これは、OSによってプロセスに提供された出力バッファーを超えます。OSは、一部のプロセスがそのバッファーから読み取るまでブロックします。したがって、現在推奨されている方法ではsubprocess.run(..)「これはデフォルトでstdoutまたはstderrをキャプチャしません」と正確に何が行われますか。ほのめかす?subprocess.check_output(..)STDERR についてはどうですか?
Evgeni Sergeev 2016年

2
@Pittoはい、しかしそれは例によって実行されるものではありません。にecho渡された文字列の前に注意してPopenください。したがって、完全なコマンドはになりますecho my mama didnt love me && rm -rf /
Chris Arndt、2018

6
これは間違いなく間違いです。ほとんどの人が必要subprocess.run()か、それより古い兄弟などsubprocess.check_call()。これらでは不十分な場合については、を参照してくださいsubprocess.Popen()os.popen()おそらくまったく言及されるべきではないか、あるいは「あなた自身のfork / exec / spawnコードをハック」した後でさえ来るべきです。
tripleee

358

典型的な実装:

import subprocess

p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,
retval = p.wait()

stdoutパイプ内のデータを自由に操作できます。実際、これらのパラメータ(stdout=stderr=)を省略すれば、のように動作しますos.system()


44
.readlines()すべての行を一度に読み取ります。つまり、サブプロセスが終了する(パイプの最後を閉じる)までブロックします。あなたはできる(バッファリングの問題が存在しない場合)、リアルタイムで読み取るには:for line in iter(p.stdout.readline, ''): print line,
JFS

1
「バッファリングの問題がない場合」とはどういう意味ですか?プロセスが確実にブロックされると、サブプロセス呼び出しもブロックされます。私の元の例でも同じことが起こります。バッファリングに関して他に何が起こり得ますか?
EmmEff

15
子プロセスは、ラインバッファリングの代わりに非インタラクティブモードでブロックバッファリングを使用する可能性があるため、子がバッファをいっぱいにするまで、データは表示されません(最後はp.stdout.readline()noですs)。子が多くのデータを生成しない場合、出力はリアルタイムではありません。Qの2番目の理由を参照してください:なぜパイプ(popen())を使用しないのですか?この回答ではいくつかの回避策が提供されています(pexpect、pty、stdbuf)
jfs

4
バッファリングの問題は、リアルタイムで出力したい場合にのみ重要であり、すべてのデータが受信されるまで何も出力しないコードには適用されません
jfs

3
この答えは、当時は問題ありませんでしたがPopen、単純なタスクにはお勧めしません。これも不必要に指定しますshell=Truesubprocess.run()答えの1つを試してください。
tripleee 2018

230

子プロセスを呼び出し側から切り離す(子プロセスをバックグラウンドで開始する)ためのいくつかのヒント。

CGIスクリプトから長いタスクを開始するとします。つまり、子プロセスはCGIスクリプト実行プロセスよりも長く存続する必要があります。

サブプロセスモジュールドキュメントの古典的な例は次のとおりです。

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

ここでの考え方は、longtask.pyが終了するまで「call subprocess」の行で待機したくないということです。しかし、例からの「ここにいくつかのより多くのコード」の行の後に何が起こるかは明らかではありません。

私のターゲットプラットフォームはFreeBSDでしたが、開発はWindows上で行われたため、最初にWindowsで問題に直面しました。

Windows(Windows XP)では、longtask.pyが作業を完了するまで、親プロセスは完了しません。これは、CGIスクリプトに必要なものではありません。この問題はPythonに固有のものではありません。PHPコミュニティでも問題は同じです。

解決策は、DETACHED_PROCESS プロセス作成フラグをWindows APIの基になるCreateProcess関数に渡すことです。pywin32をインストールした場合は、win32processモジュールからフラグをインポートできます。それ以外の場合は、自分で定義する必要があります。

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

/ * UPD 2015.10.27 @eryksunのコメントの下に、意味的に正しいフラグはCREATE_NEW_CONSOLE(0x00000010)であると記載されています* /

FreeBSDでは、別の問題があります。親プロセスが終了すると、子プロセスも終了します。そして、それもCGIスクリプトに必要なものではありません。いくつかの実験では、問題はsys.stdoutの共有にあるように見えました。そして実用的な解決策は次のとおりです:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

私は他のプラットフォームでコードをチェックしていませんし、FreeBSDでの動作の理由もわかりません。誰かが知っている場合は、あなたのアイデアを共有してください。Pythonでのバックグラウンドプロセスの開始をググリングしても、まだ何もわかりません。


私はpydev + eclipseでpy2exeアプリを開発する際の「癖」の可能性に気づきました。Eclipseの出力ウィンドウが終了していないため、メインスクリプトが切り離されていないことがわかりました。スクリプトが完了まで実行されても、戻りを待機しています。しかし、py2exe実行可能ファイルにコンパイルしようとすると、予期した動作が発生します(プロセスをデタッチとして実行してから終了します)。よくわかりませんが、実行可能ファイルの名前がプロセスリストに含まれていません。これは、すべてのアプローチ(os.system( "start *")、os.P_DETACHを使用したos.spawnl、サブプロシージャなど)で機能します
maranas

1
CREATE_NEW_PROCESS_GROUPフラグも必要になる場合があります。直接の子プロセスが終了した場合でも子プロセスを待機するPopenを
jfs

5
次は正しくありません:「[o] nウィンドウ(win xp)、親プロセスはlongtask.pyが作業を完了するまで完了しません。」親は正常に終了しますが、コンソールウィンドウ(conhost.exeインスタンス)は、最後に接続されたプロセスが終了したときにのみ閉じ、子は親のコンソールを継承した可能性があります。で設定すると、子がコンソールを継承または作成できないようにすることでこれDETACHED_PROCESScreationflags回避します。代わりに新しいコンソールが必要な場合は、CREATE_NEW_CONSOLE(0x00000010)を使用します。
Eryk Sun、2015

1
分離プロセスとして実行することが正しくないという意味ではありませんでした。そうは言っても、標準のハンドルをファイル、パイプに設定する必要があるかもしれませんos.devnull。子プロセスが親プロセスと同時にユーザーと対話するようにする場合は、新しいコンソールを作成します。1つのウィンドウで両方を実行しようとすると混乱を招くでしょう。
Eryk Sun、2015

1
プロセスをバックグラウンドで実行するOSに依存しない方法はありませんか?
チャーリーパーカー

152
import os
os.system("your command")

コマンドはクリーンアップされていないため、これは危険であることに注意してください。「os」モジュールと「sys」モジュールの関連ドキュメントについては、Googleにお任せします。同様のことを行う関数(exec *とspawn *)がたくさんあります。


6
私が10年近く前に何を意味しているのかはわかりません(日付を確認してください!)。
nimish

1
これはsubprocess、やや多目的でポータブルなソリューションであることを示しています。もちろん、外部コマンドの実行は本質的に移植性がなく(サポートする必要のあるすべてのアーキテクチャでコマンドが使用可能であることを確認する必要があります)、外部コマンドとしてユーザー入力を渡すことは本質的に安全ではありません。
tripleee 2018

1
この男のタイムスタンプに注意してください。「正しい」回答は投票数が40倍で、回答#1です。
nimish

NodeJSのものを実行するために私のために働いた1つのソリューション。
ニコライシンダ

148

os.systemの代わりにsubprocessモジュールを使用することをお勧めします。これは、シェルのエスケープが行われるため、はるかに安全だからです。

subprocess.call(['ping', 'localhost'])

パラメータを使用してコマンドからリスト作成するsubprocess場合はshell=False、when で使用できるリストを使用shlex.splitして、これを簡単に行うためにdocs.python.org/2/library/shlex.html#shlex.split(それはドキュメントに応じて推奨される方法ですdocs.python.org/2/library/subprocess.html#popen-constructor
ダニエル・F

6
これは正しくありません:「シェルのエスケープが行われるため、はるかに安全です」。サブプロセスはシェルエスケープを行わず、サブプロセスはコマンドをシェルに渡さないため、シェルエスケープする必要はありません。
リーライアン

144
import os
cmd = 'ls -al'
os.system(cmd)

コマンドの結果を返したい場合は、を使用できますos.popen。ただし、バージョン2.6以降、サブプロセスモジュールが推奨されるため、これは非推奨です。他の回答でも十分にカバーされています。


10
popen subprocessを支持して非推奨になりました。
Fox Wilson

たとえばos.system( 'ls -l> test2.txt')のようにUNIXシェル自体のように機能するため、os.system呼び出しで結果を保存することもできます
Stefan Gruenwald

97

Pythonで外部コマンドを呼び出すことができるさまざまなライブラリがたくさんあります。各ライブラリーについて説明し、外部コマンドを呼び出す例を示しました。例として使用したコマンドはls -l(すべてのファイルをリストする)です。ライブラリの詳細を知りたい場合は、各ライブラリのドキュメントを一覧表示してリンクしました。

出典:

これらはすべてのライブラリです。

うまくいけば、これがどのライブラリを使用するかを決定するのに役立ちます:)

サブプロセス

サブプロセスを使用すると、外部コマンドを呼び出して、それらのコマンドを入力/出力/エラーパイプ(stdin、stdout、およびstderr)に接続できます。コマンドを実行するためのデフォルトの選択はサブプロセスですが、他のモジュールの方が優れている場合もあります。

subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command

os

osは「オペレーティングシステムに依存する機能」に使用されます。os.systemandを使用して外部コマンドを呼び出すこともできますos.popen(注:subprocess.popenもあります)。osは常にシェルを実行し、を使用する必要がない、または使用方法がわからない人のための単純な代替手段ですsubprocess.run

os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output

sh

shは、プログラムを関数のように呼び出すことができるサブプロセスインターフェイスです。これは、コマンドを複数回実行する場合に役立ちます。

sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function

鉛直

plumbumは、「スクリプトのような」Pythonプログラム用のライブラリです。のような関数のようなプログラムを呼び出すことができますsh。Plumbumは、シェルなしでパイプラインを実行する場合に役立ちます。

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command

期待する

pexpectを使用すると、子アプリケーションを生成して制御し、出力からパターンを見つけることができます。これは、Unixでttyを期待するコマンドのサブプロセスのより良い代替手段です。

pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')

ファブリック

ファブリックは、Python 2.5および2.7ライブラリです。ローカルおよびリモートのシェルコマンドを実行できます。ファブリックは、セキュアシェル(SSH)でコマンドを実行するための単純な代替手段です

fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output

特使

特使は「人間のためのサブプロセス」として知られています。これは、subprocessモジュールの便利なラッパーとして使用されます。

r = envoy.run("ls -l") # Run command
r.std_out # get output

コマンド

commandsにはラッパー関数が含まれていますが、より優れた代替策であるos.popenため、Python 3から削除されsubprocessました。

この編集は、JFセバスチャンのコメントに基づいています。



73

"pexpect" Pythonライブラリも確認してください。

ssh、ftp、telnetなどの外部プログラム/コマンドをインタラクティブに制御できます。次のように入力するだけです。

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')

70

標準ライブラリを使用

サブプロセスモジュール(Python 3)を使用します

import subprocess
subprocess.run(['ls', '-l'])

推奨される標準的な方法です。ただし、より複雑なタスク(パイプ、出力、入力など)を作成して作成するのは面倒です。

Pythonバージョンに関する注意:Python 2をまだ使用している場合、subprocess.callは同様の方法で機能します。

ProTipは:shlex.splitは、あなたがのためにコマンドを解析することができruncallおよびその他のsubprocess場合の関数は、あなたがしたくない(または、あなたがすることはできません!)のリストの形でそれらを提供します。

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

外部依存関係あり

外部の依存関係を気にしない場合は、plumbumを使用します。

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

最高のsubprocessラッパーです。これはクロスプラットフォームです。つまり、WindowsとUnixライクなシステムの両方で動作します。によるインストールpip install plumbum

別の人気のあるライブラリはshです。

from sh import ifconfig
print(ifconfig('wlan0'))

ただし、shWindowsのサポートが終了したため、以前ほど素晴らしいものではありません。によるインストールpip install sh


69

呼び出すコマンドからの出力が必要な場合は、subprocess.check_output(Python 2.7+)を使用できます。

>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

シェルパラメータにも注意してください。

shellがのTrue場合、指定されたコマンドはシェルを介して実行されます。これは、Pythonを主に拡張制御フローに使用していて、ほとんどのシステムシェルで提供されているにもかかわらず、シェルパイプ、ファイル名のワイルドカード、環境変数の展開、ユーザーの家への〜の展開など、他のシェル機能への便利なアクセスが必要な場合に役立ちます。ディレクトリ。パイソン自体は(特に、多くの貝殻のような機能の実装を提供することをしかし、ノートglobfnmatchos.walk()os.path.expandvars()os.path.expanduser()、およびshutil)。


1
check_output文字列ではなくリストが必要なことに注意してください。引用符で囲まれたスペースに頼らずに呼び出しを有効にする場合、これを行う最も簡単で最も読みやすい方法はsubprocess.check_output("ls -l /dev/null".split())です。
Bruno Bronosky、2018年

56

これがコマンドの実行方法です。このコードには、必要なものがすべて含まれています

from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()

3
読みやすさを向上させるのであれば、ハードコードされたコマンドは許容できると思います。
Adam Matan 14

54

更新:

subprocess.runコードが以前のバージョンのPythonとの互換性を維持する必要がない場合は、Python 3.5以降の推奨アプローチです。より一貫性があり、Envoyと同様の使いやすさを提供します。(ただし、配管は簡単ではありません。方法については、この質問を参照してください。)

ドキュメントの例をいくつか示します

プロセスを実行します。

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

失敗した実行で発生:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

キャプチャ出力:

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

元の答え:

Envoyを試すことをお勧めします。これはサブプロセスのラッパーであり、古いモジュールと関数を置き換えることを目的としています。特使は人間のサブプロセスです。

READMEの使用例:

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)

>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''

周りのものもパイプします:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]


36

os.system大丈夫ですが、少し時代遅れです。また、あまり安全ではありません。代わりに、を試してくださいsubprocesssubprocessshを直接呼び出さないため、より安全ですos.system

詳細については、こちらをご覧ください


2
私は全体的な推奨事項に同意しsubprocessますが、すべてのセキュリティ問題を削除するわけではなく、独自の厄介な問題があります。
tripleee

36

Pythonで外部コマンドを呼び出す

単純なを使用してsubprocess.runCompletedProcessオブジェクトを返します。

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

どうして?

Python 3.5以降、ドキュメントではsubprocess.runを推奨しています。

サブプロセスを呼び出すための推奨されるアプローチは、処理できるすべてのユースケースでrun()関数を使用することです。より高度なユースケースでは、基礎となるPopenインターフェースを直接使用できます。

これが可能な最も単純な使用法の例です-要求どおりに実行します:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

runコマンドが正常に終了するのを待ってから、CompletedProcessオブジェクトを返します。代わりにTimeoutExpiredtimeout=引数を指定した場合)またはCalledProcessError(失敗してを渡した場合)が発生する可能性がありますcheck=True

上記の例から推測できるように、stdoutとstderrはどちらもデフォルトで独自のstdoutとstderrにパイプされます。

返されたオブジェクトを検査して、指定されたコマンドと戻りコードを確認できます。

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

出力のキャプチャ

出力をキャプチャする場合はsubprocess.PIPE、適切なstderrまたはに渡すことができますstdout

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(バージョン情報がstdoutではなくstderrに入れられるのは興味深いし、少し直観に反しているようです。)

コマンドリストを渡す

手動でコマンド文字列を提供すること(質問が示唆するように)から、プログラムで構築された文字列を提供することへと簡単に移行できます。プログラムで文字列を構築しないでください。これは潜在的なセキュリティ問題です。入力を信頼していないと想定することをお勧めします。

>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n  This is indented.\r\n'

注:args位置的にのみ渡す必要があります。

完全な署名

これは、ソース内の実際の署名で、次のように表示されhelp(run)ます。

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

popenargskwargsに与えられるPopenコンストラクタ。サブプロセスのstdinにパイプされるinputバイトの文字列(または、encodingまたはを指定する場合はUnicode universal_newlines=True)にすることができます。

ドキュメントでは説明timeout=し、check=True私ができるよりよいです:

タイムアウト引数はPopen.communicate()に渡されます。タイムアウトになると、子プロセスは強制終了され、待機されます。子プロセスが終了した後、TimeoutExpired例外が再度発生します。

チェックがtrueで、プロセスがゼロ以外の終了コードで終了する場合、CalledProcessError例外が発生します。その例外の属性は、引数、終了コード、およびキャプチャされた場合のstdoutとstderrを保持します。

この例check=Trueは、私が思いつくものよりも優れています:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

拡張署名

ドキュメントにあるように、拡張されたシグネチャは次のとおりです。

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, 
shell=False, cwd=None, timeout=None, check=False, encoding=None, 
errors=None)

これは、argsリストのみが定位置で渡されることを示していることに注意してください。したがって、残りの引数をキーワード引数として渡します。

ポペン

Popen代わりに使用する場合?私は議論だけに基づいてユースケースを見つけるのに苦労します。Popenただし、を直接使用するとpoll、、「send_signal」、「terminate」、「wait」などのメソッドにアクセスできます。

これPopen、ソースで指定された署名です。これは(とは対照的にhelp(Popen))最も正確な情報のカプセル化だと思います。

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, encoding=None, errors=None):

しかし、より有益であるドキュメントはPopen

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
                 stdout=None, stderr=None, preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

新しいプロセスで子プログラムを実行します。POSIXでは、クラスはos.execvp()のような動作を使用して子プログラムを実行します。Windowsでは、このクラスはWindows CreateProcess()関数を使用します。Popenの引数は次のとおりです。

残りのドキュメントを理解Popenすることは、読者のための演習として残します。


プライマリプロセスとサブプロセス間の双方向通信の簡単な例は、こちらにあります。stackoverflow.com
James Hirschorn

最初の例では、おそらくshell=Trueコマンドをリストとして渡すか、(より良い)リストとして渡す必要があります。
tripleee

33

Plumbumもあります

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns

28

使用する:

import os

cmd = 'ls -al'

os.system(cmd)

os-このモジュールは、オペレーティングシステムに依存する機能を使用するポータブルな方法を提供します。

その他のos機能については、こちらのドキュメントをご覧ください


2
また、非推奨です。サブプロセスを使用する
Corey Goldberg

28

これは簡単なことです。

import os
cmd = "your command"
os.system(cmd)

1
これはPEP-324でより詳細に説明されている欠点を指摘することに失敗しています。のドキュメントos.systemでは、を優先して回避することを明示的に推奨していsubprocessます。
tripleee 2018

25

私はその単純さのためにshell_commandがとても好きです。サブプロセスモジュールの上に構築されています。

ドキュメントの例を次に示します。

>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py  shell_command.py  test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan  391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0

24

ここには、前に述べていない別の違いがあります。

subprocess.Popen<command>をサブプロセスとして実行します。私の場合、別のプログラム<b>と通信する必要があるファイル<a>を実行する必要があります。

サブプロセスを試してみましたが、実行に成功しました。ただし、<b>は<a>と通信できませんでした。ターミナルから両方を実行すると、すべてが正常です。

もう1つ:(注:kwriteは他のアプリケーションとは動作が異なります。Firefoxで以下を試した場合、結果は同じにはなりません。)

を実行しようとするとos.system("kwrite")、ユーザーがkwriteを閉じるまでプログラムフローが停止します。それを克服するために代わりに試してみましたos.system(konsole -e kwrite)。今回はプログラムは流れ続けましたが、kwriteはコンソールのサブプロセスになりました。

誰もがサブプロセスではないkwriteを実行します(つまり、システムモニターでは、ツリーの左端に表示される必要があります)。


1
「誰でもサブプロセスではないkwriteを実行するとはどういう意味ですか?
Peter Mortensen

23

os.system結果を保存することはできません。そのため、結果を何らかのリストなどに保存したい場合はsubprocess.call機能します。


22

subprocess.check_call戻り値をテストしたくない場合に便利です。エラーが発生すると例外がスローされます。


22

私はサブプロセスshlexと一緒に使用する傾向があります(引用文字列のエスケープを処理するため):

>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)

17

恥知らずなプラグ、私はこれのためのライブラリを書いた:P https://github.com/houqp/shell.py

それは基本的に今のところpopenとshlexのラッパーです。また、パイピングコマンドもサポートしているため、Pythonでコマンドを簡単にチェーンできます。したがって、次のようなことができます。

ex('echo hello shell.py') | "awk '{print $2}'"

16

Windowsではあなただけインポートすることができsubprocess、モジュールをして呼び出すことで外部コマンドを実行しsubprocess.Popen()subprocess.Popen().communicate()そしてsubprocess.Popen().wait()以下のように:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)

出力:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K

15

Linuxでは、独立して実行する(Pythonスクリプトの終了後も実行を継続する)外部コマンドを呼び出す場合は、タスクスプーラーまたはatコマンドとして単純なキューを使用できます。

タスクスプーラーの例:

import os
os.system('ts <your-command>')

タスクスプーラーに関する注意事項(ts):

  1. 実行する並行プロセスの数(「スロット」)を次のように設定できます。

    ts -S <number-of-slots>

  2. インストールにtsは管理者権限は必要ありません。シンプルなを使用してソースからダウンロードしてコンパイルmakeし、パスに追加すれば完了です。


1
ts私が知っているどのディストリビューションでも標準ではありませんが、へのポインタatは少し便利です。あなたもおそらく言及する必要がありbatchます。他の場所と同様に、os.system()推奨事項では、少なくともそれsubprocessが推奨される置き換えであることをおそらく言及する必要があります。
tripleee

15

Popenを使用して、プロシージャのステータスを確認できます。

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

subprocess.Popenをチェックしてください。


15

OpenStack NeutronからネットワークIDを取得するには:

#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print $2 }'"
temp = os.popen(netid).read()  /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)

nova net-listの出力

+--------------------------------------+------------+------+
| ID                                   | Label      | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1      | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External   | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal   | None |
+--------------------------------------+------------+------+

print(networkId)の出力

27a74fcd-37c0-4789-9414-9531b7e3f126

os.popen()2016年にはお勧めしません。Awkスクリプトは、ネイティブのPythonコードに簡単に置き換えることができます。
tripleee 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.