Python – subprocess でコマンドを実行する方法

目次

概要

Python の subprocess でコマンドを実行する方法ついて解説します。

subprocess.run

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

args で指定されたコマンドを実行します。

コマンドの指定方法

コマンドは引数も含めて文字列で指定する方法とコマンド及び引数をリストで指定する方法の2通りがあります。

文字列で指定する場合、shell=True を指定します。

In [1]:
import subprocess

subprocess.run(["echo hoge"], shell=True)
CompletedProcess(args=['echo hoge'], returncode=0)

shell=True を指定しないと、echo hoge で1つのコマンドと解釈され、FileNotFoundError 例外が発生します。

subprocess.run(["echo hoge"])
# FileNotFoundError: [Errno 2] No such file or directory: 'echo hoge'

コマンド及び引数をリストで指定する場合は次のようになります。リストで指定するメリットとして、引数のエスケープが必要な場合に自動で行われることです。(例: ファイル名に空白が含まれる場合)

In [2]:
subprocess.run(["echo", "hoge fuga"])
CompletedProcess(args=['echo', 'hoge fuga'], returncode=0)

標準入力、標準出力、標準エラー出力

  • stdin: 標準入力
  • stdout: 標準出力
  • stderr: 標準エラー出力

これらはプログラムの標準入力、標準出力、および標準エラー出力のファイルハンドルを指定します。stdinstdoutstderr には以下が指定できます。

  • subprocess.PIPE: パイプ
  • subprocess.DEBNULL: null デバイス (/dev/null)
  • ファイルオブジェクト: open() などで作成したファイル記述子
  • None: リダイレクトしない
  • encoding または errors を指定したか、text=True を指定した場合、ファイルオブジェクトが指定された stdinstdoutstderr はテキストモードで開かれます。
  • stderr=subprocess.STDOUT を指定した場合、標準エラー出力を標準出力にリダイレクトします。
  • encoding はファイルオブジェクトを開く際のエンコーディングを指定します。
  • errors はエンコードやデコードの際のエラーをどのように扱うかを指定します。
  • stdin において、\n は行の区切り文字として扱われます。

制限時間を設定する

timeout を指定した場合、timeout 秒経過して処理が完了していない場合、子プロセスは kill され、TimeoutExpired 例外が送出されます。

In [3]:
try:
    subprocess.run(["sleep", "5"], timeout=1)
except subprocess.TimeoutExpired as e:
    print(e.cmd)
    print(e.timeout)
    print(e.output)
    print(e.stdout)
    print(e.stderr)
['sleep', '5']
0.9999595480039716
None
None
None

プログラムが正常終了したかどうかを判定する

check=True を指定した場合、実行したプロセスのリターンコードが0でない場合は CalledProcessError 例外を送出します。

In [4]:
try:
    subprocess.run(["sleep"], check=True)
except subprocess.CalledProcessError as e:
    print(e.cmd)
    print(e.returncode)
    print(e.output)
    print(e.stdout)
    print(e.stderr)
['sleep']
1
None
None
None

結果を受け取る

文字列で受け取る

capture_output=True, text=True を引数に指定します。結果は subprocess.run() の返り値の CompletedProcess オブジェクトの stdout、stderr 属性で取得できます。

In [5]:
ret = subprocess.run(["ls", "-la"], capture_output=True, text=True)
print("コマンド", ret.args)
print("リターンコード", ret.returncode)
print("標準出力", ret.stdout)
print("標準エラー出力", ret.stderr)
コマンド ['ls', '-la']
リターンコード 0
標準出力 total 16
drwxr-xr-x  2 root root 4096 Sep  4 07:19 .
drwxr-xr-x 16 root root 4096 Sep  4 06:13 ..
-rw-r--r--  1 root root 7058 Sep  4 07:19 post.ipynb

標準エラー出力 

ファイルに出力する

stout にファイルオブジェクトを渡すと、標準出力をファイルに出力できます。標準エラー出力も同じファイルに出力したい場合は stderr=subprocess.STDOUT を指定して、標準エラー出力を標準出力にリダイレクトします。

In [6]:
f = open("date.txt", "w")
ret = subprocess.run(["date"], stdout=f, stderr=subprocess.STDOUT)

入力を行う

以下のように2つの入力を要求されるプログラムがあった場合、与える入力を input 引数に指定できます。 文字列中の \n は、手動で入力したときに Enter キーで1つの入力を完了されることに相当します。

add.py

x = int(input("x:"))
y = int(input("y:"))

print(x + y)
In [7]:
stdin = "1\n5"
ret = subprocess.run(["python", "add.py"], input=stdin, capture_output=True, text=True)
print(ret.stdout)
x:y:6

コメント

コメントする

目次