fnmatch本质是字符串匹配工具,不扫描文件系统;它按完整路径匹配,不自动提取basename,仅支持、?、[abc]等shell通配符,不支持*或正则语法,且大小写行为依赖平台,无内置case_sensitive参数。

fnmatch 本质是字符串匹配工具,不是文件系统扫描器——它只比对名字,不读目录、不检查是否存在。
fnmatch.fnmatch() 的实际行为和常见误用
它把输入字符串当作完整路径名(含斜杠)来匹配,fnmatch.fnmatch("a/b/c.txt", "*/c.*") 返回 True,但 fnmatch.fnmatch("a/b/c.txt", "c.*") 是 False。很多人误以为它会自动拆分路径或只匹配 basename。
- 若只想匹配文件名部分,先用
os.path.basename()或pathlib.Path().name提取 -
?匹配任意单字符,*匹配任意多字符(包括空),[abc]匹配方括号内任一字符 - 注意:它不支持
**(递归通配)、不识别{a,b}、也不等价于 shell 的 glob 扩展逻辑
fnmatch.filter() 和 os.listdir() 的组合陷阱
直接写 fnmatch.filter(os.listdir("."), "*.py") 看似方便,但结果里混着子目录名,且无法区分文件/目录——filter() 不做类型判断,只筛字符串。
- 需要严格过滤普通文件时,得配合
os.path.isfile()或pathlib.Path.is_file() - 若路径含中文或特殊编码,确保当前环境 locale 与文件系统一致,否则可能因字节 vs 字符比较出错
- 性能上,
os.listdir()+fnmatch.filter()比glob.glob()略快(无隐式 stat 调用),但少了一层路径解析保障
大小写敏感性由系统决定,不能靠 fnmatch 参数控制
fnmatch 本身没有 case_sensitive 参数。它的行为取决于底层 OS 的文件系统和 Python 的 locale 设置:
立即学习“Python免费学习笔记(深入)”;
- Linux/macOS 默认大小写敏感:
fnmatch.fnmatch("Readme.md", "readme.*")→False - Windows 下通常不敏感,但若路径来自 WSL 或网络挂载,可能意外敏感
- 如需跨平台稳定行为,统一转小写再匹配:
fnmatch.fnmatch(name.lower(), pattern.lower())
真正容易被忽略的是:fnmatch 不处理 Unicode 归一化——比如带重音符号的字母(é vs e\u0301)会被视为不同字符,而某些文件系统会自动归一化名称,导致匹配失败。


















