os.walk()跳过子目录或文件因权限受限、符号链接、挂载点等,默认不进入软链接;需用dirs[:]原地过滤、try/except捕获异常、正则用re.search()匹配路径末尾、shutil.rmtree()配onerror回调修正权限,删除前务必dry run验证。

用 os.walk() 遍历目录时,为什么跳过了某些子目录或文件?
常见现象是只清除了当前目录下的临时文件,深层嵌套的 .log 或 __pycache__ 没被扫到。根本原因是 os.walk() 默认不修改遍历行为,而有些目录(如权限受限、符号链接、挂载点)会被自动跳过,且它不会递归进入软链接指向的路径。
实操建议:
- 传入
followlinks=False(默认值)确保安全;若需处理符号链接,显式设为True并加try/except捕获OSError - 在
for root, dirs, files in os.walk(...)循环中,可对dirs列表原地过滤,比如删掉以.开头的隐藏目录:dirs[:] = [d for d in dirs if not d.startswith('.')] - 遇到
PermissionError时不要中断整个遍历,用try/except包裹单次os.remove()或shutil.rmtree()
正则匹配文件名时,re.match() 和 re.search() 哪个更合适?
re.match() 只从字符串开头匹配,而垃圾文件名往往带路径前缀(如 /tmp/project/__pycache__/foo.cpython-311.pyc),直接对完整路径用 match() 几乎总失败。
实操建议:
- 统一用
re.search(r'\.(tmp|log|swp)$|__pycache__|\.DS_Store', filename)—— 注意锚定结尾用$,避免误杀myapp.log.bak - 若匹配目标是扩展名,优先用
os.path.splitext(filename)[1].lower()判断,比正则快且稳定;正则留作复杂模式(如cache_202405.*\.dat) - 编译正则对象一次复用:
PATTERN = re.compile(r'\.(tmp|log|swp)$|__pycache__'),避免循环里反复编译
删除 __pycache__ 或大日志时,shutil.rmtree() 报 PermissionError 怎么办?
典型错误信息:PermissionError: [WinError 5] 拒绝访问: 'C:\xxx\__pycache__'(Windows)或 PermissionError: [Errno 13] Permission denied: '/var/log/myapp/'(Linux)。这不是代码写错,而是目标目录有只读属性、执行位缺失,或进程正在占用其中文件。
实操建议:
- 给
shutil.rmtree()加onerror回调函数,捕获并修正权限后重试:
def handle_remove_error(func, path, exc):
import stat
if not os.access(path, os.W_OK):
os.chmod(path, stat.S_IWUSR)
func(path)
else:
raise
shutil.rmtree(path, onerror=handle_remove_error)
- Linux/macOS 下,确认没其他 Python 进程在该目录运行(
lsof +D /path/to/dir) - Windows 下,关闭资源管理器窗口或 IDE 的文件索引功能,它们常独占
__pycache__
清理脚本上线前必须验证的三件事
自动删文件没有后悔键。哪怕逻辑看似简单,真实环境里一个路径拼错就可能清掉项目源码。
实操建议:
- 所有删除操作前加
print()或日志输出完整绝对路径:print(f"[DRY RUN] Would remove: {os.path.abspath(full_path)}"),先跑一遍确认范围 - 用
os.path.getsize()过滤小文件(如),避开误删关键配置(<code>.env、config.yaml虽然也带点,但通常不小) - 排除白名单路径:硬编码禁止删除
/home/username/.local、C:\Users\XXX\AppData等敏感位置,哪怕匹配上也跳过
最易被忽略的是时间戳判断——别一上来就删所有 .log,先加 os.path.getmtime() 筛选 7 天前的,否则可能干掉正在轮转的活跃日志。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











