Python PR

Pythonからコマンドを実行したり、Pythonコードを実行したりする方法【サブプロセスの管理】

記事内に商品プロモーションを含む場合があります

この記事では、Pythonのコード内からコマンドプロンプトやターミナルのコマンドを実行したり、Pythonコードを実行する方法を解説します。

これらの実行はサブプロセスとして管理します。

それでは、サブプロセスを起動し、コマンドラインを操作してみましょう!

使用した環境

Windows11 Python 3.11.5

サブプロセスの起動

サブプロセスを起動するには、subprocessモジュールのrun()関数を使います。

構文

import subprocess

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)

戻り値の型

<class 'subprocess.CompletedProcess'>

解説

argsで指定されたコマンドを実行し、コマンドの完了を待ってCompletedProcessインスタンスを返します。argsには文字列あるいはプログラム引数のシーケンスを指定できますが、基本的には引数のシーケンスを渡す方が良いです。

Pythonコードの実行

Pythonコードtest.pysubprocess.run()関数を使って実行してみます。test.pyprint()関数を使ってTESTと出力するだけのモジュールです。

import subprocess

# プログラム引数のシーケンス
seq = ['python', 'test.py']

# サブプロセスの起動
subprocess.run(seq)

実行結果

TEST

TESTと出力され、test.pyが実行されたのがわかります。もしコマンドライン引数を渡したい場合は以下のようにシーケンスに追加します。

seq = ['python', 'test.py', 'コマンドライン引数1', 'コマンドライン引数2']

コマンドの実行

コマンドをsubprocess.run()関数を使って実行してみます。Windowsの場合、shellの組み込みコマンドを実行するにはshell=Trueとする必要がある。

import subprocess

# Unix/Linux
seq = ['ls']
subprocess.run(seq)

# Windows 組み込み
seq = ['dir']
subprocess.run(seq, shell=True)

# Windows 外部コマンド
seq = ['whoami']
subprocess.run(seq)

オプションやファイル名を指定したい場合はシーケンスに追加します。

seq = ['dir', '/p', '/s']

注意: OSコマンドインジェクション

shell=Trueにすると「OSコマンドインジェクションの脆弱性」を生む可能性があります。できるだけ使わないように注意してください。

どうしても必要な場合は、公式サイトをよく読んでから実装してください。

外部Linkセキュリティで考慮すべき点 - subprocess --- サブプロセス管理 — Python 3.12.0 ドキュメント

また、OSコマンドインジェクションについて理解し、きちんと対策を打っておきましょう!

外部LinkOSコマンドインジェクションの仕組みとその対策 | セキュリティ対策 | CyberSecurityTIMES

非同期で実行する

サブプロセスを非同期で起動するには、subprocess.Popen()コンストラクタを使います。Popenオブジェクトでは、wait()kill()などのメソッドを呼び出すことができます。

構文

import subprocess

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=None, 
                 startupinfo=None, creationflags=0, restore_signals=True, 
                 start_new_session=False, pass_fds=(), 
                 *, group=None, extra_groups=None, user=None, 
                 umask=- 1, encoding=None, errors=None, text=None, 
                 pipesize=- 1, process_group=None)

戻り値の型

<class 'subprocess.Popen'>

例としてtest.pyを非同期で実行してみる。test.pyはコマンドライン引数で適当な文字列とインターバルを受け取り、文字列と現在時刻をインターバルだけ待機しながら3回出力する。

import subprocess

seq = ['python', 'test.py', 'test1', '1']
p1 = subprocess.Popen(seq)

seq = ['python', 'test.py', 'test2', '2']
p2 = subprocess.Popen(seq)

p1.wait()
p2.wait()

test.py

import datetime as dt
import sys
import time

s = sys.argv[1]
interval = float(sys.argv[2])

for i in range(3):
    print(s, dt.datetime.now())
    time.sleep(interval)

実行結果

test1 2023-10-23 16:36:28.532482
test2 2023-10-23 16:36:28.534502
test1 2023-10-23 16:36:29.533592
test1 2023-10-23 16:36:30.534622
test2 2023-10-23 16:36:30.535261
test2 2023-10-23 16:36:32.536604

まとめ

この記事では、Pythonでサブプロセスを起動する方法を解説しました。

subprocessモジュールを使うことでコマンドやファイルを実行できたりとコマンドラインで行えることは一通り処理することができました。

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ