この記事では、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.py
をsubprocess.run()
関数を使って実行してみます。test.py
はprint()
関数を使って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
モジュールを使うことでコマンドやファイルを実行できたりとコマンドラインで行えることは一通り処理することができました。
それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ