概要(shutil.rmtree は「ディレクトリ丸ごと削除」を一発で行う強力な関数)
shutil.rmtree は、ディレクトリとその中身(ファイル・サブディレクトリ)を再帰的にすべて削除します。空でなくても消せるため便利ですが、誤指定すると取り返しがつきません。最重要ポイントは「削除対象の検証」「権限・読み取り専用の扱い」「失敗時のハンドリング」の3つ。pathlib と組み合わせて安全確認を徹底し、必要なら onerror で復旧してから削除します。
基本の使い方(ここが重要)
ディレクトリツリーを丸ごと削除する
import shutil
shutil.rmtree("build") # build/ 配下をすべて削除
Python指定パスがディレクトリで、その中身がどれだけあっても削除されます。ファイル単体の削除は rmtree ではなく Path.unlink を使います。
pathlib と併用して「存在・種別」を確認する
from pathlib import Path
import shutil
target = Path("dist")
if target.exists() and target.is_dir():
shutil.rmtree(target)
Python存在はするがディレクトリでないケース(同名ファイル)を事前に弾くと事故が減ります。
重要ポイントの深掘り(安全性・権限・失敗時の復旧)
削除対象の安全確認(ベース配下か、危険パスでないか)
from pathlib import Path
def ensure_under(base: Path, p: Path) -> Path:
base = base.resolve(); p = p.resolve()
if p == base or base in p.parents:
return p
raise ValueError("ベース外の削除は不可")
base = Path.cwd()
target = ensure_under(base, Path("build/artifacts"))
Python誤ってホームやシステム領域を指定しないよう、「ベース配下のみ許可」などのガードを入れます。
読み取り専用(Windows)の削除失敗を onerror で解決
読み取り専用属性で PermissionError になるときは、onerror コールバックで属性変更後に再試行します。
import os, stat, shutil
def make_writable(func, path, exc_info):
# path を書き込み可能にして再試行
os.chmod(path, stat.S_IWRITE)
func(path)
shutil.rmtree("build", onerror=make_writable)
Pythonignore_errors=True は「失敗を無視」して進みますが、片付けが中途半端になり得るため、基本は onerror で対処する方が安全です。
「空ディレクトリだけ」なら rmdir(対比理解)
from pathlib import Path
Path("empty_dir").rmdir() # 空なら削除、空でないと OSError
Pythonrmtree は中身ごと、rmdir は空だけ。用途に応じて使い分けます。
実務での使いどころ(クリーンアップ・再生成・一括掃除)
ビルド成果物のクリーンアップ(削除→再作成)
from pathlib import Path
import shutil
out = Path("build")
if out.exists():
shutil.rmtree(out)
out.mkdir(parents=True, exist_ok=True)
Python毎回クリーンな出力先を用意できます。
テンポラリの掃除(存在チェック+失敗時メッセージ)
from pathlib import Path
import shutil
tmp = Path("tmp/session_001")
try:
if tmp.exists():
shutil.rmtree(tmp)
except PermissionError:
print("権限不足で削除できません:", tmp)
Python運用では例外を捕まえてログを残すだけでも調査がしやすくなります。
glob と併用して複数フォルダを一括削除
from pathlib import Path
import shutil
for d in Path("logs").glob("old_*"):
if d.is_dir():
shutil.rmtree(d)
Pythonパターンで対象を選び、ディレクトリのみ削除します。必要なら sorted で順序を固定します。
よくある落とし穴の回避(誤指定・権限・巨大ツリー)
誤指定防止(表示確認・ドライラン)
大規模削除の前に「対象一覧を表示」して確認する習慣をつけます。ドライランを用意するとより安全です。
from pathlib import Path
import shutil
def dry_run_rmtree(p: Path):
print("削除対象:", p.resolve())
for q in p.rglob("*"):
print(" -", q)
target = Path("build")
dry_run_rmtree(target)
# 実行フェーズ
shutil.rmtree(target)
Python権限・ロックで削除できない時の方針
- 読み取り専用属性は onerror で解除して再試行。
- 別プロセスがファイルを掴んでいる場合は、プロセス終了後に再試行する設計を検討。
巨大ツリーの削除時間と途中失敗
大量ファイルの削除は時間がかかります。途中で失敗した場合に「残骸があっても次回掃除できる」よう、再実行可能なスクリプトにしておくと安心です。
例題で身につける(定番から一歩先まで)
例題1:安全ガード付き rmtree
from pathlib import Path
import shutil
def safe_rmtree(p: Path, base: Path):
p = p.resolve(); base = base.resolve()
if p == base or base in p.parents:
if p.exists() and p.is_dir():
shutil.rmtree(p)
else:
raise ValueError(f"危険な削除要求: {p}")
safe_rmtree(Path("build/artifacts"), Path.cwd())
Python例題2:Windows 読み取り専用対応 onerror
import os, stat, shutil
def onerror(func, path, exc_info):
try:
os.chmod(path, stat.S_IWRITE)
func(path)
except Exception:
raise
shutil.rmtree("build", onerror=onerror)
Python例題3:rmtree と rmdir の違いを確認
from pathlib import Path
import shutil
Path("work/a/b").mkdir(parents=True, exist_ok=True)
try:
Path("work/a").rmdir() # 中身があるので失敗
except OSError:
print("rmdir は空のみ")
shutil.rmtree("work") # ツリーごと削除
Pythonまとめ
shutil.rmtree は「空でなくてもディレクトリを丸ごと消せる」強力な削除関数です。誤指定を防ぐためにベース配下チェックやドライランを入れ、pathlib で存在・種別を検証。読み取り専用での失敗は onerror で属性を直して再試行し、ignore_errors の安易な使用は避ける。巨大ツリーや実運用では、例外ハンドリングと再実行可能な設計をセットにしておくと、短く安全で頼れるクリーンアップ処理になります。
