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

