Categories: Python

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

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

ゆうまる

独学でプログラミングを勉強しているおじさん。いろんな言語を勉強したが浅く広くなためあまり仕事につながらない。また忘れっぽいため自分のブログを備忘録としても使っている。産まれてこのかたずっとネコを飼ってる生粋のネコ派。最近お腹が出てきて筋トレに奮闘中!

Recent Posts

【Dart】コンストラクタのデフォルト引数について

Dartのコンストラクタのデフォルト引数…

2週間 ago

【Unity】有料アセットを無料で手に入れる方法

この記事では、Unityの有料アセットを…

4か月 ago

【Python】任意の秒数だけ処理を一時停止する方法【sleep()関数】

この記事では、Pythonで任意の秒数だ…

1年 ago

【Python】Wordの文書の新規作成と読み書き

この記事では、Pythonを使ってWor…

1年 ago

【Python】メタクラスって結局なんなの?

この記事では、Pythonのメタクラスに…

1年 ago

【Unity】割合から数値に数値から割合に変換する

この記事では、割合から数値に変換する関数…

1年 ago