2026-10-06 · 喵窝资源铺
场景:下载文件夹 / 微信接收目录里几百个 未命名文档(1).docx、photo (1).jpg、IMG_2024 bak.jpg。Windows 自带 F2 一个个改太慢;网上脚本大多直接 os.rename 一把梭——这篇的版本默认预览、加 --go 才执行。文中代码实跑验证,真实输出贴在下面。
| 输入 | 处理 |
|---|---|
(1) (2) 下载重复后缀 | 去掉扩展名前的 (N);撞名自动加 _2 _3 |
| 文件名里的空格 | 压缩多余空格并换成下划线(--nounderscore 可关) |
| 安全 | 默认 dry-run 只打印改名计划;--go 才执行;两阶段改名防互相覆盖 |
#!/usr/bin/env python3
"""批量重命名:默认 dry-run 预览,--go 才真正执行。
用法: python3 rename.py 目录 [--go] [--nounderscore]
"""
import argparse, os, re, sys
def plan(d, underscore=True):
renames, used = [], set(os.listdir(d))
for name in sorted(os.listdir(d)):
if name == os.path.basename(__file__): continue
new = re.sub(r'\s*\(\d+\)(?=\.[^.]+$)', '', name) # 去掉扩展名前的 (1)
new = re.sub(r'\s+', ' ', new).strip() # 压缩空格
if underscore: new = new.replace(' ', '_')
if new == name: continue
base, ext = os.path.splitext(new); cand, i = new, 1
while cand in used and cand != name:
i += 1; cand = f"{base}_{i}{ext}"
used.discard(name); used.add(cand)
renames.append((name, cand))
return renames
if __name__ == '__main__':
ap = argparse.ArgumentParser()
ap.add_argument('dir'); ap.add_argument('--go', action='store_true')
ap.add_argument('--nounderscore', action='store_true')
a = ap.parse_args()
ren = plan(a.dir, not a.nounderscore)
if not ren: print('无需重命名'); sys.exit(0)
for old, new in ren: print(f'{old} -> {new}')
if a.go:
# 先全部改临时名再改最终名,避免 A->B 与 B->C 互相覆盖
tmp = [(o, f'__tmp__{i}') for i, (o, _) in enumerate(ren)]
for o, t in tmp: os.rename(os.path.join(a.dir, o), os.path.join(a.dir, t))
for (_, t), (_, n) in zip(tmp, ren): os.rename(os.path.join(a.dir, t), os.path.join(a.dir, n))
print(f'已重命名 {len(ren)} 个文件')
else:
print('(预览模式,确认无误后加 --go 执行)')
测试目录放 5 个典型脏文件名:
IMG_2024 bak.jpg -> IMG_2024_bak.jpg photo (1).jpg -> photo.jpg photo (2).jpg -> photo_2.jpg 未命名文档(1).docx -> 未命名文档_2.docx
加 --go 后 ls 复核:IMG_2024_bak.jpg、photo.jpg、photo_2.jpg、未命名文档.docx、未命名文档_2.docx——与预览完全一致。注意 未命名文档(1) 撞上已有的 未命名文档,自动落成 未命名文档_2 而不是覆盖。
photo.jpg 和 photo (1).jpg 时,改名计划是 photo(1)→photo(冲突让它落 _2 才安全);但更一般的场景:计划里有 a→b 和 b→c,若按列表顺序直接 os.rename,先执行 a→b,原 b 还没来得及改成 c 就被覆盖,文件被吞且无任何报错。解法是两阶段:先全部改成 __tmp__0/1/2...,再从临时名改成最终名。photo_2.jpg,会被后处理的另一个 photo (2).jpg 撞上。所以 used 集合每落定一个新名字都要 add、腾出的旧名字 discard,冲突检测才闭环。清理完文件名,下一步往往是统一文档格式/加页码/批量转 PDF——这些都有实跑过的教程:Word 批量转 PDF、PDF 批量加页码、Word 批量查找替换。不想装环境折腾?把文件发给我们代做(¥9.9 起,做不对免费重做;虚拟物品交付后不退款)。