应使用 onerror 回调处理 PermissionError,如通过 os.chmod(path, stat.S_IWRITE) 解除只读属性;ignore_errors 会静默掩盖错误,不推荐线上使用;无需预检目录存在性,直接 try/except 捕获 FileNotFoundError 即可。

shutil.rmtree 删除非空目录时 PermissionError 怎么办
直接调用 shutil.rmtree 删除带只读文件或系统属性的目录,Windows 上大概率报 PermissionError: [WinError 5] 拒绝访问;Linux/macOS 则可能卡在 sticky 位或权限不足的子目录。这不是函数写错了,而是它默认不处理文件属性——它只管删,不管“能不能删”。
- 必须提前给所有子项解除只读(
os.chmod(path, stat.S_IWRITE)) - Windows 下还要处理
stat.FILE_ATTRIBUTE_HIDDEN和stat.FILE_ATTRIBUTE_SYSTEM - 推荐用
onerror回调统一兜底,而不是先遍历再 chmod(避免竞态和重复操作)
示例回调写法:
import os
import stat
import shutil
def _remove_readonly(func, path, _):
os.chmod(path, stat.S_IWRITE)
func(path)
shutil.rmtree("mydir", onerror=_remove_readonly)
shutil.rmtree 的 ignore_errors 和 onerror 到底选哪个
ignore_errors=True 是最省事的开关,但它会静默吞掉所有错误——包括磁盘满、路径不存在、甚至误删了挂载点里的内容。线上脚本里用这个等于埋雷。
-
onerror更可控:你能区分是权限问题、路径不存在,还是设备忙,然后做不同响应 - 如果只是想跳过个别顽固文件(比如被进程锁住的日志),
onerror+pass比ignore_errors更明确 -
ignore_errors在 CI/CD 或自动化部署中容易掩盖真实故障,调试成本反而更高
删除前要不要先检查目录是否存在或是否为目录
不用。因为 shutil.rmtree 本身对非目录路径会抛 NotADirectoryError,对不存在路径会抛 FileNotFoundError——这两个异常类型清晰,比手动 os.path.isdir 多一次系统调用还多一层竞态风险。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 如果你要“删掉就完事”,直接 try/except 捕获
FileNotFoundError即可(表示本来就没有) - 如果逻辑上要求“必须存在且是目录才删”,那就捕获
NotADirectoryError并报错 - 别用
os.path.exists做预检:检查完到执行rmtree之间可能被其他进程改掉
Python 3.12+ 中 unlink/mkdir 的新行为会影响 shutil.rmtree 吗
不影响。虽然 os.unlink 和 os.rmdir 在 3.12 加了 missing_ok 参数,但 shutil.rmtree 底层仍走老路径,没用上这个优化。它依然依赖 os.listdir → 逐个 os.unlink/os.rmdir → 出错进 onerror 这套流程。
- 这意味着你不能指望
shutil.rmtree(path, missing_ok=True)—— 这个参数根本不存在 - 跨平台兼容性也没变:Windows 下仍需处理 ACL 和句柄占用;Linux 下仍要小心 NFS 挂载点或 proc/sysfs 子目录
- 真正要注意的是:某些容器环境(如 rootless Podman)里,
rmtree可能因用户命名空间限制失败,这时得换subprocess.run(["rm", "-rf"]),但代价是失去 Python 异常控制流
递归删除看着简单,实际卡点全在边界条件:权限、竞态、挂载点、运行时上下文。写的时候少想“怎么删”,多想“删不掉时程序该知道什么”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










