Python スクリプト内から (Unix シェルまたは Windows コマンド プロンプトで入力したように) 外部コマンドを呼び出すにはどうすればよいですか?
63 に答える
subprocess
標準ライブラリのモジュールを使用します。
import subprocess
subprocess.run(["ls", "-l"])
subprocess.run
overの利点はos.system
、より柔軟であることです ( 「実際の」ステータス コードstdout
、より優れたエラー処理などを取得できます)。stderr
のドキュメントでos.system
さえ、代わりに使用することを推奨していsubprocess
ます:
この
subprocess
モジュールは、新しいプロセスを生成し、その結果を取得するためのより強力な機能を提供します。この関数を使用するよりも、そのモジュールを使用することをお勧めします。役立つレシピについては、ドキュメントの「古い関数をサブプロセス モジュールに置き換える」セクションを参照してください。subprocess
Python 3.4 以前では、subprocess.call
代わりに.run
次を使用します。
subprocess.call(["ls", "-l"])
長所と短所を含む、外部プログラムを呼び出す方法の要約:
os.system
コマンドと引数をシステムのシェルに渡します。この方法で一度に複数のコマンドを実際に実行し、パイプと入力/出力のリダイレクトを設定できるため、これは便利です。例えば:os.system("some_command < input_file | another_command > output_file")
ただし、これは便利ですが、スペースなどのシェル文字のエスケープを手動で処理する必要があります。一方、これにより、実際には外部プログラムではなく、単なるシェル コマンドであるコマンドを実行することもできます。
os.popen
os.system
そのプロセスの標準入出力にアクセスするために使用できるファイルのようなオブジェクトを提供することを除いて、 と同じことを行います。popen には他に 3 つのバリアントがあり、すべて i/o の処理が少し異なります。すべてを文字列として渡すと、コマンドがシェルに渡されます。それらをリストとして渡す場合、エスケープについて心配する必要はありません。例:print(os.popen("ls -l").read())
subprocess.Popen
. これは の代替として意図されて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 つの統一されたクラスにすべてのオプションがあると便利です。ドキュメントを参照してください。
subprocess.call
. これは基本的にPopen
クラスと同じで、すべて同じ引数を取りますが、コマンドが完了して戻りコードが返されるまで待機するだけです。例えば:return_code = subprocess.call("echo Hello World", shell=True)
subprocess.run
. Python 3.5+ のみ。上記に似ていますが、さらに柔軟でCompletedProcess
、コマンドの実行が終了したときにオブジェクトを返します。os.fork
,os.exec
,os.spawn
は C 言語のものと似ていますが、直接使用することはお勧めしません。
subprocess
モジュールはおそらくあなたが使用するものであるべきです。
最後に、シェルによって実行される最終コマンドを文字列として渡すすべてのメソッドについて、それをエスケープする責任があることに注意してください。渡す文字列の一部が完全に信頼できない場合、セキュリティに重大な影響があります。たとえば、ユーザーが文字列の一部または一部を入力している場合です。不明な場合は、これらのメソッドを定数でのみ使用してください。影響のヒントを得るために、次のコードを検討してください。
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
my mama didnt love me && rm -rf /
そして、ユーザーがファイルシステム全体を消去できる何か " " を入力したと想像してください。
典型的な実装:
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()
。
呼び出しプロセスから子プロセスを切り離す (子プロセスをバックグラウンドで開始する) ためのいくつかのヒント。
CGI スクリプトから長いタスクを開始したいとします。つまり、子プロセスは、CGI スクリプト実行プロセスよりも長く存続する必要があります。
subprocess モジュールのドキュメントの古典的な例は次のとおりです。
import subprocess
import sys
# Some code here
pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess
# Some more code here
ここでの考え方は、longtask.py が終了するまで「call subprocess」の行で待機したくないということです。しかし、例の「some more code here」という行の後に何が起こるかは明確ではありません。
私のターゲット プラットフォームは 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 でのバックグラウンド プロセスの開始に関するグーグル検索は、まだ何の光も当てていません。
import os
os.system("your command")
コマンドは消去されないため、これは危険であることに注意してください。「os」および「sys」モジュールの関連ドキュメントについては、グーグルで検索してください。同様のことを行う関数 (exec* と spawn*) がたくさんあります。
os.system の代わりにsubprocessモジュールを使用することをお勧めします。これは、シェルエスケープを行うため、はるかに安全だからです。
subprocess.call(['ping', 'localhost'])
import os
cmd = 'ls -al'
os.system(cmd)
コマンドの結果を返したい場合は、 を使用できますos.popen
。ただし、これはバージョン 2.6 以降、他の回答で十分にカバーされているsubprocess モジュールを支持して廃止されました。
Python で外部コマンドを呼び出すことができるさまざまなライブラリが多数あります。各ライブラリについて説明し、外部コマンドを呼び出す例を示しました。例として使用したコマンドはls -l
(list all files) です。ライブラリについて詳しく知りたい場合は、それぞれのドキュメントをリストしてリンクしています。
ソース
- サブプロセス: https://docs.python.org/3.5/library/subprocess.html
- シュレックス: https://docs.python.org/3/library/shlex.html
- OS: https://docs.python.org/3.5/library/os.html
- sh: https://amoffat.github.io/sh/
- プラムバム: https://plumbum.readthedocs.io/en/latest/
- pexpect: https://pexpect.readthedocs.io/en/stable/
- ファブリック: http://www.fabfile.org/
- 特使: https://github.com/kennethreitz/envoy
- コマンド: https://docs.python.org/2/library/commands.html
これらはすべてのライブラリです
これが、使用するライブラリを決定するのに役立つことを願っています:)
サブプロセス
サブプロセスを使用すると、外部コマンドを呼び出して、それらを入力/出力/エラー パイプ (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.system
andを使用して外部コマンドを呼び出すためにも使用できます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.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')
ファブリック
fabric は 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
特使
envoy は「人間のためのサブプロセス」として知られています。モジュールの便利なラッパーとして使用されsubprocess
ます。
r = envoy.run("ls -l") # Run command
r.std_out # Get output
コマンド
commands
のラッパー関数が含まれていますが、より優れた代替手段であるos.popen
ため、Python 3 から削除されました。subprocess
標準ライブラリで
サブプロセス モジュール(Python 3)を使用します。
import subprocess
subprocess.run(['ls', '-l'])
おすすめのスタンダードな方法です。ただし、より複雑なタスク (パイプ、出力、入力など) を作成して記述するのは面倒です。
Python バージョンに関する注意: まだ Python 2 を使用している場合、subprocess.callは同様に機能します。
プロのヒント: shlex.splitrun
は、 、call
、およびその他のsubprocess
関数をリスト形式で提供したくない場合 (または提供できない場合) に、それらのコマンドを解析するのに役立ちます。
import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))
外部依存関係あり
外部依存関係を気にしない場合は、plumbuを使用してください:
from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
最高のsubprocess
ラッパーです。クロスプラットフォームです。つまり、Windows と Unix 系のシステムの両方で動作します。によってインストールしpip install plumbum
ます。
別の人気のあるライブラリはshです。
from sh import ifconfig
print(ifconfig('wlan0'))
ただし、sh
Windows のサポートが終了したため、以前ほど素晴らしいものではありません。によってインストールしpip install sh
ます。
私はいつもfabric
このようなものを使用します:
from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )
しかし、これは良いツールのようです: sh
(Python subprocess interface) .
例を見てください:
from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
「pexpect」Python ライブラリもチェックしてください。
外部プログラム/コマンド、さらには ssh、ftp、telnet などをインタラクティブに制御できます。次のように入力するだけです。
child = pexpect.spawn('ftp 192.168.0.24')
child.expect('(?i)name .*: ')
child.sendline('anonymous')
child.expect('(?i)password')
呼び出しているコマンドからの出力が必要な場合は、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'
シェルパラメータにも注意してください。
シェルがの場合
True
、指定されたコマンドはシェルを介して実行されます。これは、Pythonを主にほとんどのシステムシェルで提供する拡張制御フローに使用していて、シェルパイプ、ファイル名ワイルドカード、環境変数の拡張、ユーザーのホームへの〜の拡張などの他のシェル機能への便利なアクセスが必要な場合に役立ちます。ディレクトリ。ただし、Python自体が多くのシェルのような機能(特に、、、、、、、、)の実装を提供していることに注意glob
してください。fnmatch
os.walk()
os.path.expandvars()
os.path.expanduser()
shutil
アップデート:
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を試すことをお勧めします。これは subprocess のラッパーであり、古いモジュールと関数を置き換えることを目的としています。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'>]
これが私のコマンドの実行方法です。このコードには、必要なものがすべて含まれています
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()
os.system
大丈夫ですが、ちょっと時代遅れです。また、あまり安全ではありません。代わりに、試してみてくださいsubprocess
。 subprocess
は sh を直接呼び出さないため、 より安全ですos.system
。
詳細については、こちらをご覧ください。
プラムバムもあります
>>> 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
使用する:
import os
cmd = 'ls -al'
os.system(cmd)
os - このモジュールは、オペレーティング システムに依存する機能を使用する移植可能な方法を提供します。
os
その他の機能については、こちらのドキュメントをご覧ください。
次のように簡単にできます。
import os
cmd = "your command"
os.system(cmd)
os.system
結果を保存することはできないので、結果をリストなどに保存したい場合は、うまくいきますsubprocess.call
。
ここには、前述されていない別の違いがあります。
subprocess.Popen
<command> をサブプロセスとして実行します。私の場合、別のプログラム <b> と通信する必要があるファイル <a> を実行する必要があります。
サブプロセスを試したところ、実行に成功しました。しかし、<b> は <a> と通信できませんでした。ターミナルから両方を実行すると、すべて正常です。
もう 1 つ: (注: kwrite は他のアプリケーションとは異なる動作をします。Firefox で以下を試すと、結果は同じにはなりません。)
を試みるとos.system("kwrite")
、ユーザーが kwrite を閉じるまでプログラム フローがフリーズします。それを克服するために、代わりに試しましたos.system(konsole -e kwrite)
。今回もプログラムは続きましたが、kwriteはコンソールのサブプロセスになりました。
誰でも、サブプロセスではない kwrite を実行します (つまり、システム モニターでは、ツリーの左端に表示される必要があります)。
私はsubprocessを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)
subprocess.check_call
戻り値をテストしたくない場合に便利です。エラーが発生すると例外がスローされます。
Linux では、独立して実行される (Python スクリプトが終了した後も実行し続ける) 外部コマンドを呼び出したい場合は、単純なキューをタスク スプーラまたはatコマンドとして使用できます。
タスク スプーラの例:
import os
os.system('ts <your-command>')
タスク スプーラに関する注意事項 ( ts
):
実行する同時プロセスの数 (「スロット」) を次のように設定できます。
ts -S <number-of-slots>
インストール
ts
には管理者権限は必要ありません。ソースからダウンロードしてコンパイルしmake
、パスに追加するだけで完了です。
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
Popen を使用すると、手順のステータスを確認できます。
from subprocess import Popen
proc = Popen(['ls', '-l'])
if proc.poll() is None:
proc.kill()
subprocess.Popenをチェックしてください。
簡単な方法はos モジュールを使用することです:
import os
os.system('ls')
または、サブプロセス モジュールを使用することもできます。
import subprocess
subprocess.check_call('ls')
結果を変数に格納する場合は、次を試してください。
import subprocess
r = subprocess.check_output('ls')
コマンドを実行して結果を返す最も簡単な方法:
from commands import getstatusoutput
try:
return getstatusoutput("ls -ltr")
except Exception, e:
return None
ここに私の2セントがあります:私の見解では、これは外部コマンドを扱うときのベストプラクティスです...
これらは execute メソッドからの戻り値です...
pass, stdout, stderr = execute(["ls","-la"],"/home/user/desktop")
これは実行方法です...
def execute(cmdArray,workingDir):
stdout = ''
stderr = ''
try:
try:
process = subprocess.Popen(cmdArray,cwd=workingDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1)
except OSError:
return [False, '', 'ERROR : command(' + ' '.join(cmdArray) + ') could not get executed!']
for line in iter(process.stdout.readline, b''):
try:
echoLine = line.decode("utf-8")
except:
echoLine = str(line)
stdout += echoLine
for line in iter(process.stderr.readline, b''):
try:
echoLine = line.decode("utf-8")
except:
echoLine = str(line)
stderr += echoLine
except (KeyboardInterrupt,SystemExit) as err:
return [False,'',str(err)]
process.stdout.close()
returnCode = process.wait()
if returnCode != 0 or stderr != '':
return [False, stdout, stderr]
else:
return [True, stdout, stderr]
議論に追加するだけで、Python コンソールの使用を含めると、IPythonから外部コマンドを呼び出すことができます。IPython プロンプトでは、接頭辞「!」を付けてシェル コマンドを呼び出すことができます。Python コードをシェルと組み合わせて、シェル スクリプトの出力を Python 変数に割り当てることもできます。
例えば:
In [9]: mylist = !ls
In [10]: mylist
Out[10]:
['file1',
'file2',
'file3',]
いくつかの調査の後、私にとって非常にうまく機能する次のコードがあります。基本的に、標準出力と標準エラーの両方をリアルタイムで出力します。
stdout_result = 1
stderr_result = 1
def stdout_thread(pipe):
global stdout_result
while True:
out = pipe.stdout.read(1)
stdout_result = pipe.poll()
if out == '' and stdout_result is not None:
break
if out != '':
sys.stdout.write(out)
sys.stdout.flush()
def stderr_thread(pipe):
global stderr_result
while True:
err = pipe.stderr.read(1)
stderr_result = pipe.poll()
if err == '' and stderr_result is not None:
break
if err != '':
sys.stdout.write(err)
sys.stdout.flush()
def exec_command(command, cwd=None):
if cwd is not None:
print '[' + ' '.join(command) + '] in ' + cwd
else:
print '[' + ' '.join(command) + ']'
p = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
)
out_thread = threading.Thread(name='stdout_thread', target=stdout_thread, args=(p,))
err_thread = threading.Thread(name='stderr_thread', target=stderr_thread, args=(p,))
err_thread.start()
out_thread.start()
out_thread.join()
err_thread.join()
return stdout_result + stderr_result
Python シェル スクリプトを作成していて、システムにIPythonがインストールされている場合は、bang プレフィックスを使用して IPython 内でシェル コマンドを実行できます。
!ls
filelist = !ls
ここでは、外部コマンドを呼び出して、コマンドの出力を返すか出力します。
Python Subprocess check_output は次の場合に適しています
引数を指定してコマンドを実行し、その出力をバイト文字列として返します。
import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc
Python 3.5+ では、 subprocess モジュールの run 関数を使用することをお勧めします。これによりCompletedProcess
オブジェクトが返され、そこから出力と戻りコードを簡単に取得できます。
from subprocess import PIPE, run
command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)
2015 年の更新: Python 3.5 では、subprocess.Popen よりもはるかに使いやすいsubprocess.runが追加されました。私はそれをお勧めします。
>>> 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"], capture_output=True)
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', stderr=b'')
Linux コマンドを実行する最も簡単な方法は、Python モジュールのPopen
関数を使用することです。subprocess
その中で、Popen.communicate()
関数はコマンド出力を提供します。例えば
import subprocess
..
process = subprocess.Popen(..) # Pass command and arguments to the function
stdout, stderr = process.communicate() # Get command output and error
..
os.popen()
コマンドを実行する最も簡単で安全な方法です。コマンドラインで実行する任意のコマンドを実行できます。さらに、次を使用してコマンドの出力をキャプチャすることもできますos.popen().read()
次のように実行できます。
import os
output = os.popen('Your Command Here').read()
print (output)
現在のディレクトリ内のすべてのファイルを一覧表示する例:
import os
output = os.popen('ls').read()
print (output)
# Outputs list of files in the directory