フォルダの作成、ファイル一覧の取得、プロセスの管理、アクセス権の付与——ターミナルやコマンドプロンプトで手作業していた操作が、Pythonスクリプト1本に統合できます。subprocessモジュールを使えば、WindowsのコマンドプロンプトでもMac/LinuxのターミナルでもOSのシェルコマンドをPythonから直接呼び出せるようになります。バッチ処理スクリプトとPythonコードを組み合わせたい場面で、特に威力を発揮します。
subprocessは、PythonコードからOSのシェルコマンドを実行できる標準モジュールです。WindowsならコマンドプロンプトやPowerShell、Mac/Linuxならターミナル(bash/zsh)で打ち込んでいたコマンドを、Pythonスクリプト内から呼び出せます。
標準モジュールなので、pip install は不要で import subprocess だけで使えます。
💡 フォルダ作成やファイル操作だけなら
osモジュールやpathlibでも実現できます。subprocessの出番は「シェルコマンドで書いた方がラク」「外部ツールをPythonから呼びたい」と感じたときです。
subprocess.run() が最もシンプルで汎用的な関数です。第1引数にコマンド文字列を渡し、shell=True を指定するだけでコマンドが実行されます。
import subprocess
# Windowsの例:testというフォルダを作成
subprocess.run("mkdir test", shell=True) このコードを実行すると、Pythonスクリプトと同じ階層に test フォルダが作成されます。たったこれだけです。
コマンドの出力をPython側で受け取りたい場合は、capture_output=True と text=True を追加します。戻り値の CompletedProcess オブジェクトから各種情報を取り出せます。
import subprocess
# testフォルダ内のファイル一覧を取得(Windows)
cp = subprocess.run(
r"dir .\test",
shell=True,
capture_output=True,
text=True
)
print(cp.stdout) # コマンドの標準出力(文字列)
print(cp.returncode) # 正常終了なら 0、エラーなら 0以外
print(cp.stderr) # エラーメッセージ(なければ空文字) text=True 時)0、エラー → 0 以外の整数存在しないディレクトリに対してコマンドを実行すると、returncode は 0 以外になり、stderr にエラーメッセージが格納されます。この値を使って「コマンド成功時だけ次の処理を実行する」といった分岐が書けます。
コマンドが長時間応答しないケースに備えて、timeout 引数で実行時間の上限を設定できます。指定秒数を超えると subprocess.TimeoutExpired 例外が発生するので、try/except で捕捉します。
import subprocess
try:
cp = subprocess.run(
"some_long_command",
shell=True,
capture_output=True,
text=True,
timeout=5 # 5秒でタイムアウト
)
print(cp.stdout)
except subprocess.TimeoutExpired:
print("タイムアウトしました。処理を中断します。")
たとえばキー入力待ちで止まってしまうコマンドなど、Pythonプログラムが無限待機に陥る危険を防げます。
WindowsでPowerShellのコマンドをsubprocessから呼び出すには、powershell -command "..." の形式で第1引数に指定します。パスにバックスラッシュが含まれる場合は raw文字列プレフィックス r を付けておくと安全です。
import subprocess
cp = subprocess.run(
r'powershell -command "Get-ChildItem C:\Users"',
shell=True,
capture_output=True,
text=True
)
print(cp.stdout) PowerShellコマンドを二重引用符で囲み、run()の引数全体はシングル引用符で囲むのがポイントです。
Mac/Linuxでも書き方はほぼ同じです。コマンドをbash/zsh用に変えるだけで動作します。
import subprocess
# Mac/Linux:カレントディレクトリのファイル一覧
cp = subprocess.run(
"ls -la ./test",
shell=True,
capture_output=True,
text=True
)
print(cp.stdout) バッチ処理スクリプトやOS操作の自動化は、複数のターミナルウィンドウを並べて作業することが多くなります。広い画面とキーボード環境を整えるだけで、開発効率が大きく変わります🚀
shell=True にすると、コマンドをシェル(cmd.exeやbash)経由で実行します。パイプ(|)やワイルドカード(*)などシェル機能が使えます。shell=False(デフォルト)では、コマンドをリスト形式(["ls", "-la"])で渡して直接実行します。信頼できないユーザー入力をコマンドに含める場合は、セキュリティ上 shell=False の方が安全です。
capture_output を指定しない場合、コマンドの出力はそのままターミナル画面に表示されますが、Python変数として受け取ることはできません。cp.stdout は None になります。Python側で出力を処理・加工したい場合は必ず capture_output=True と text=True を指定してください。
subprocess.run() に check=True を追加すると、returncode が 0 以外のとき自動で subprocess.CalledProcessError 例外を発生させられます。try/except subprocess.CalledProcessError でまとめてエラー処理を書けるので、returncode を自分でチェックする手間が省けます。
subprocess.run() はコマンドの完了を待ってから制御を返す「同期実行」です。一方 subprocess.Popen() はコマンドを非同期で起動し、Pythonコードと並行して処理できる「非同期実行」に対応しています。複数のコマンドを同時に走らせたい場合や、コマンドの実行中にPython側で別の処理を続けたい場合は Popen を使います。
使えません。コマンド文字列はOS固有のものになります。クロスプラットフォームで動かしたい場合は、sys.platform や platform.system() でOSを判定し、分岐してコマンドを切り替える方法が一般的です。または、ファイル操作の範囲なら pathlib や shutil モジュールを使ってOS差異を吸収する方が堅牢です。
subprocessモジュールの基本は「subprocess.run(コマンド文字列, shell=True)」の一行から始まります。capture_output=True と text=True を加えれば出力を文字列として受け取れ、returncode でコマンドの成否を確認、timeout でハングアップを防げます。PythonコードとシェルコマンドをうまくミックスさせることでOS操作の自動化がさらに強力になります。シェルコマンドで書いた方が楽な処理に出くわしたときは、ぜひsubprocessを活用してみてください⚙️✨