序章

Python 3には、外部プログラムを実行し、Pythonコードでそれらの出力を読み取るためのサブプロセスモジュールが含まれています。

あなたが見つけるかもしれません subprocess Pythonコード内からコンピューター上で別のプログラムを使用する場合に便利です。 たとえば、Pythonコード内から git を呼び出して、プロジェクト内で追跡されているファイルを取得したい場合があります。 git バージョン管理。 あなたがあなたのコンピュータでアクセスできるどんなプログラムもによって制御されることができるので subprocess、ここに示す例は、Pythonコードから呼び出す可能性のあるすべての外部プログラムに適用できます。

subprocess いくつかのクラスと関数が含まれていますが、このチュートリアルでは、 subprocessの最も便利な関数:subprocess.run。 そのさまざまな使用法と主なキーワード引数を確認します。

前提条件

このチュートリアルを最大限に活用するには、Python3でのプログラミングにある程度精通していることをお勧めします。 必要な背景情報については、次のチュートリアルを確認できます。

外部プログラムの実行

あなたは使用することができます subprocess.run Pythonコードから外部プログラムを実行する関数。 ただし、最初に、をインポートする必要があります subprocess と sys プログラムへのモジュール:

import subprocess
import sys

result = subprocess.run([sys.executable, "-c", "print('ocean')"])

これを実行すると、次のような出力が表示されます。

Output
ocean

この例を確認してみましょう。

  • sys.executable は、プログラムが最初に呼び出されたPython実行可能ファイルへの絶対パスです。 例えば、 sys.executable 次のようなパスかもしれません /usr/local/bin/python.
  • subprocess.run 実行しようとしているコマンドのコンポーネントで構成される文字列のリストが表示されます。 最初に渡す文字列は sys.executable、私たちは指示しています subprocess.run 新しいPythonプログラムを実行します。
  • The -c コンポーネントは python 実行するPythonプログラム全体で文字列を渡すことができるコマンドラインオプション。 この場合、文字列を出力するプログラムを渡します ocean.

あなたは私たちが渡すリストの各エントリについて考えることができます subprocess.run スペースで区切られているように。 例えば、 [sys.executable, "-c", "print('ocean')"] 大まかに次のように変換されます /usr/local/bin/python -c "print('ocean')". ご了承ください subprocess 基盤となるオペレーティングシステムで実行する前に、コマンドのコンポーネントを自動的に引用符で囲みます。たとえば、スペースを含むファイル名を渡すことができます。

警告:信頼できない入力をに渡さないでください subprocess.run. 以来 subprocess.run コンピュータ上で任意のコマンドを実行する機能があり、悪意のある攻撃者がそれを使用して予期しない方法でコンピュータを操作する可能性があります。

外部プログラムからの出力のキャプチャ

これで、を使用して外部プログラムを呼び出すことができます subprocess.run、そのプログラムからの出力をキャプチャする方法を見てみましょう。 たとえば、このプロセスは、 git ls-files 現在バージョン管理下に保存されているすべてのファイルを出力します。

注:このセクションに示されている例には、Python3.7以降が必要です。 特に、 capture_outputtext キーワード引数は、2018年6月にリリースされたPython3.7で追加されました。

前の例に追加しましょう:

import subprocess
import sys

result = subprocess.run(
    [sys.executable, "-c", "print('ocean')"], capture_output=True, text=True
)
print("stdout:", result.stdout)
print("stderr:", result.stderr)

このコードを実行すると、次のような出力が返されます。

Output
stdout: ocean stderr:

この例は、最初のセクションで紹介した例とほぼ同じです。印刷するサブプロセスをまだ実行しています ocean. 重要なのは、しかし、私たちは合格します capture_output=Truetext=True キーワード引数 subprocess.run.

subprocess.run にバインドされているsubprocess.CompletedProcessオブジェクトを返します result. The subprocess.CompletedProcess オブジェクトには、外部プログラムの終了コードとその出力に関する詳細が含まれています。 capture_output=True を保証します result.stdoutresult.stderr 外部プログラムからの対応する出力が入力されます。 デフォルトでは、 result.stdoutresult.stderr バイトとしてバインドされますが、 text=True キーワード引数は、代わりにバイトを文字列にデコードするようにPythonに指示します。

出力セクションでは、 stdoutocean (さらに、末尾の改行 print 暗黙的に追加します)、 stderr.

空でない値を生成する例を試してみましょう stderr:

import subprocess
import sys

result = subprocess.run(
    [sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True
)
print("stdout:", result.stdout)
print("stderr:", result.stderr)

このコードを実行すると、次のような出力が返されます。

Output
stdout: stderr: Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops

このコードはPythonサブプロセスを実行し、すぐに ValueError. 決勝戦を検査するとき result、何も表示されません stdoutTraceback 私たちの ValueErrorstderr. これは、デフォルトでPythonが書き込みを行うためです。 Traceback 未処理の例外の stderr.

不正な終了コードで例外を発生させる

実行するプログラムが不正な終了コードで終了した場合に、例外を発生させると便利な場合があります。 ゼロコードで終了するプログラムは成功したと見なされますが、ゼロ以外のコードで終了するプログラムはエラーが発生したと見なされます。 例として、このパターンは、実行した場合に例外を発生させたい場合に役立ちます。 git ls-files 実際にはそうではなかったディレクトリ内 git リポジトリ。

使用できます check=True キーワード引数 subprocess.run 外部プログラムがゼロ以外の終了コードを返した場合に例外を発生させるには、次のようにします。

import subprocess
import sys

result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)

このコードを実行すると、次のような出力が返されます。

Output
Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 512, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

この出力は、エラーを発生させたサブプロセスを実行したことを示しています。 stderr 私たちのターミナルで。 それで subprocess.run 忠実に育てた subprocess.CalledProcessError 私たちのメインのPythonプログラムに代わって。

または、 subprocess モジュールには、 subprocess.CompletedProcess.check_returncode メソッドも含まれています。これは、同様の効果を得るために呼び出すことができます。

import subprocess
import sys

result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"])
result.check_returncode()

このコードを実行すると、次のようになります。

Output
Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode raise CalledProcessError(self.returncode, self.args, self.stdout, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

合格しなかったので check=Truesubprocess.run、正常にバインドしました subprocess.CompletedProcess インスタンスから result プログラムがゼロ以外のコードで終了した場合でも。 呼び出し result.check_returncode()ただし、 subprocess.CalledProcessError 完了したプロセスが不正なコードで終了したことを検出するためです。

タイムアウトを使用してプログラムを早期に終了する

subprocess.run が含まれています timeout 実行に時間がかかりすぎる場合に外部プログラムを停止できるようにする引数:

import subprocess
import sys

result = subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=1)

このコードを実行すると、次のような出力が返されます。

Output
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 491, in run stdout, stderr = process.communicate(input, timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate stdout, stderr = self._communicate(input, endtime, timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate self.wait(timeout=self._remaining_time(endtime)) File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait return self._wait(timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait raise TimeoutExpired(self.args, timeout) subprocess.TimeoutExpired: Command '['/usr/local/bin/python', '-c', 'import time; time.sleep(2)']' timed out after 0.9997982999999522 seconds

実行しようとしたサブプロセスは、time.sleep関数を使用してスリープしました 2 秒。 しかし、私たちは合格しました timeout=1 キーワード引数 subprocess.run 後にサブプロセスをタイムアウトします 1 2番目。 これは、私たちが subprocess.run 最終的に上げた subprocess.TimeoutExpired 例外。

に注意してください timeout キーワード引数 subprocess.run おおよそです。 Pythonは、サブプロセスの後にサブプロセスを強制終了するために最善を尽くします timeout 秒数ですが、必ずしも正確であるとは限りません。

プログラムへの入力の受け渡し

プログラムは、入力が経由で渡されることを期待する場合があります stdin.

The input キーワード引数 subprocess.run にデータを渡すことができます stdin サブプロセスの。 例えば:

import subprocess
import sys

result = subprocess.run(
    [sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater"
)

このコードを実行すると、次のような出力が返されます。

Output
underwater

この場合、バイトを渡しました underwaterinput. ターゲットサブプロセスは、sys.stdinを使用して渡されたものを読み取りました stdin (underwater)そしてそれを私たちの出力に印刷しました。

The input キーワード引数は、複数のチェーンを作成する場合に役立ちます subprocess.run あるプログラムの出力を別のプログラムへの入力として渡すことを一緒に呼び出します。

結論

The subprocess モジュールはPython標準ライブラリの強力な部分であり、外部プログラムを実行してその出力を簡単に検査できます。 このチュートリアルでは、使用方法を学びました subprocess.run 外部プログラムを制御し、入力をそれらに渡し、それらの出力を解析し、それらの戻りコードをチェックします。

The subprocess モジュールは、このチュートリアルでは取り上げなかった追加のクラスとユーティリティを公開します。 ベースラインができたので、サブプロセスモジュールのドキュメントを使用して、他の利用可能なクラスとユーティリティについて詳しく知ることができます。