Python glob.glob 的“跨平台坑”:Linux 严格区分大小写,Windows 却“睁一只眼闭一只眼”
Python glob.glob 的“跨平台坑”:Linux 严格区分大小写,Windows 却“睁一只眼闭一只眼”
ytkz大家好,我是你们的老朋友,今天来聊一个几乎每个做跨平台开发的同学都踩过的坑——Python 的 glob.glob() 在不同操作系统下的大小写敏感性差异。
你有没有遇到过这样的情况:
- 在本地 Windows 开发机上,一切正常,脚本顺利找到所有
.txt文件; - 扔到 Linux 服务器或 CI/CD 环境,突然报“文件找不到”;
- 明明文件名就是
config.txt,你写的却是Config.TXT,为什么 Windows 能跑通,Linux 就挂了?
答案就在文件系统和 glob 模块的设计上。
一、核心差异:文件系统说了算
Python 的 glob 模块模仿 Unix shell 的通配符匹配,但匹配是否区分大小写,实际上取决于底层文件系统,而不是 Python 本身刻意统一。
Linux / macOS(默认 APFS/HFS+ 区分大小写模式)
文件系统是真正区分大小写的。file.txt和File.TXT是两个完全不同的文件。
所以glob.glob("*.txt")只匹配小写.txt结尾的文件,FILE.TXT根本不会被选中。Windows(NTFS 默认行为)
文件系统是不区分大小写的(case-insensitive),但保留大小写(case-preserving)。file.txt、File.TXT、FILE.txt其实指向同一个文件。
因此glob.glob("*.txt")会匹配所有这些变体——Windows 底层在匹配时忽略了大小写。
官方文档(Python 3.12+)虽然没有直接大段强调,但社区和 Stack Overflow 上无数案例证实:glob 的模式匹配会跟随文件系统的语义。这导致跨平台代码最常见的“silent bug”——在 Windows 上“意外”多匹配,在 Linux 上“严格”漏匹配。
二、真实案例:你可能正在经历的血泪史
场景1:数据处理脚本
你写了个批量重命名工具:
import glob
for f in glob.glob("data/*.JPG"):
# 处理 JPG 文件
在 Windows 上,它能抓到 .jpg、.JPG、.JpG 所有文件,完美。
部署到 Linux 服务器,只处理了全大写的,剩下几千张小写后缀的图片被忽略……
场景2:配置文件加载
公司很多旧项目配置文件命名不规范,有人叫 settings.yaml,有人叫 Settings.YAML。
本地 Windows 测试通过,上线 Docker(Linux)容器直接崩溃。
场景3:CI/CD 流水线
GitHub Actions / GitLab CI 默认 Linux runner,Windows runner 少见。
你本地调试 OK,提交 PR 却失败——原因往往就是 glob 没抓到文件。
三、如何写出真正跨平台的 glob 代码?(推荐方案)
目标:大多数项目希望统一行为,推荐默认按区分大小写处理(更安全、更接近 Linux 生产环境),必要时显式放宽。
方案1:最推荐 —— 统一转小写后过滤(简单、可靠)
import glob
import os
pattern = "data/*.txt" # 你原本想匹配的模式
candidates = glob.glob(pattern, recursive=True)
# 无论 Windows/Linux,最终只保留真正以 .txt 结尾(忽略大小写)的文件
target_files = [
f for f in candidates
if os.path.splitext(f)[1].lower() == ".txt"
# 或者更严格:f.lower().endswith(".txt")
]
print(target_files)
优点:代码简单,一行过滤解决所有问题。
缺点:如果目录里有海量文件,先 glob 再过滤会有轻微性能开销(但通常可忽略)。
方案2:用 pathlib(Python 3.5+ 现代写法)
from pathlib import Path
folder = Path("data")
# glob 还是会受系统影响
all_txt = list(folder.glob("*.txt")) # Windows 多匹配,Linux 严格
# 推荐做法:直接用 iterdir + 后缀判断
target_files = [
p for p in folder.iterdir()
if p.is_file() and p.suffix.lower() == ".txt"
]
iterdir() 列出所有文件,再自己判断后缀,彻底绕过 glob 的系统差异。
方案3:想在 Windows 上强制“模拟区分大小写”
import glob
import os
def case_sensitive_glob(pattern):
matches = glob.glob(pattern, recursive=True)
if os.name != "nt": # 非 Windows 直接返回
return matches
# Windows 上过滤:只保留 basename 完全匹配原模式(不忽略大小写)
result = []
for m in matches:
base = os.path.basename(m)
# 如果模式是 *.txt,这里需要更智能匹配(可结合 fnmatch)
if base.lower().endswith(".txt"): # 或者更精确匹配
result.append(m)
return result
更高级的可以用 fnmatch + 自定义过滤,但大多数场景方案1或2就够了。
四、一个小彩蛋:macOS 的“隐藏雷区”
macOS 默认文件系统(APFS)是区分大小写的,但很多用户会格式化成不区分大小写的卷(尤其是从旧 HFS+ 迁移)。
所以同一套代码,在不同 Mac 上 glob 行为可能都不一样!
建议:Mac 开发者也养成“后缀转小写判断”的习惯,避免阴间 bug。
五、写在最后:跨平台开发的正确姿势
- 永远不要假设文件名大小写一致;
- 优先用
pathlib+suffix.lower()判断; - 在 README 或文档里注明:本项目假设文件名后缀不区分大小写,但代码已兼容 Linux 严格模式;
- CI 一定要用 Linux runner 测试(最严格的环境);
- 如果项目真的需要完全忽略大小写匹配,可以用
glob.glob("**/*.[tT][xX][tT]", recursive=True)这种土办法(丑但有效)。
你踩过这个坑吗?欢迎评论区分享你的“血泪经历”或更优雅的解决方案~
下期预告:Python 文件路径那些年我们踩过的“斜杠 vs 反斜杠”大坑。
点个在看,下次踩坑少一些~





