十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI批量重命名文件前,先学会干跑和备份,避免覆盖灾难

AI批量重命名文件前,先学会干跑和备份,避免覆盖灾难 前几天一个朋友找我说用AI写了个批量改文件名的脚本一跑把自己辛苦攒的资料目录整个改乱了。我问他跑之前有没有看过脚本要改哪些文件他说没看改了再说。这就是问题所在——批量重命名这种操作99%的灾难都不是因为AI写错了代码而是因为我们没搞清楚它准备覆盖谁。AI本身不会“想”太多你给它一句“帮我批量改文件名”它就老老实实按你说的写。可它不知道你那个文件夹里藏着同名旧文件、不知道某个文件正被Excel占用、不知道你有一半文件放在符号链接里、更不知道那个叫backup的目录其实是不能动的。所以这篇东西不讲那些花哨的AI黑科技就讲一件最实在的事在让AI帮你批量改文件名之前怎么把它准备覆盖的文件清单先揪出来看明白了再动手。1. 为什么批量重命名最大的坑是“覆盖”1.1 覆盖的第一层同名文件被静默替换这是最经典、也最容易被忽略的场景。一个文件夹里原本有report_2023.xlsx你让AI把所有report_*.xlsx改成report_final.xlsx跑完一看目录里只剩一个文件另一个直接被顶掉了。文件系统层面这不叫“删除”而是“覆盖写”原来的文件内容被新文件内容替代底层数据块被标记为可重用基本没有找回的余地。生活里你很难遇到这种瞬间你住在一个门牌号下突然有人拿着同样的号牌进来说你得搬走然后他住下了。文件系统就是这么不讲道理。很多人觉得“重命名”是安全的操作因为名字变了内容还在但一旦涉及目标名冲突它就变成了一次“删除新建”。AI生成的脚本里如果直接用os.rename(src, dst)这种写法在目标已存在时不同平台表现还不一样Windows下通常直接报错FileExistsError。Linux/macOS下os.rename会直接覆盖目标连提示都不给你。shutil.move在目标存在时Windows会报错macOS/Linux也会覆盖或合并目录。就这么一个细节足以让一次“AI批量改名”变成“AI批量删文件”。所以真正靠谱的脚本必须对“目标是否存在”做显式检查不能把决定权交给操作系统的默认行为。1.2 覆盖的第二层文件正被系统或软件占用还有一种“覆盖”不是文件层面而是使用层面。你电脑上开着Word里面正编辑着方案.docx你让AI把整个目录里的.docx统一加个日期前缀跑的时候Word立刻弹窗“文件被占用”然后脚本中断改了一半的目录看上去乱七八糟。这件事的隐蔽性在于不是每次都会报错。macOS和Linux上很多情况下并不锁定文件今天你在Finder/资源管理器里可能正用“快速预览”看这个文件脚本照样能把它改名看着成功了但你可能没意识到打开着的应用里那个文件的路径已经失效了。保存的时候应用要么重新创建一个新文件要么直接报错更常见的情况是应用悄悄把内容写到了一个你以为“原路径”的地方实际上已经因为路径失效产生了幽灵副本。更麻烦的是目录级占用。如果你把某个文件夹整个重命名而终端、编辑器、本地服务器进程的工作目录还停在里面后续所有相对路径读写都会静默失败日志里只有一行No such file or directory排查半天才想起来是改名改的。1.3 覆盖的第三层目录结构被打乱路径引用失效有人觉得“我只是改了文件的名字目录结构没动过”但实际上批量重命名经常一不小心就动了不该动的东西。比如你把assets/images下的文件统一改成img_001.jpg这种格式结果项目中另一处代码引用的却是icons/logo.png这个路径还在但内容对应的文件已经跑到另一个目录去了。这种问题在非代码领域更常见你的论文里引用了data/实验数据/第一轮.xlsx结果你让AI把“第一轮”改成了“round1”再打开论文里的数据透视表全部断链。Git仓库里这个问题尤其阴险。直接在文件管理器里重命名文件Git会认为是“删除新建”历史记录全没了git log里你那个文件变成了一次删除一次新增代码评审的人一脸懵。正确做法是git mv这个命令让Git知道这是一次重命名保留历史。AI写的脚本可不管你是普通目录还是Git仓库它只负责“把A改成B”。1.4 覆盖的第四层不该动的文件被纳入范围最后一层是我觉得最可怕的——AI自己“扩大打击范围”。你让它“把这个目录下所有*.jpg改成photo_xxx.jpg”它写出来的代码可能是glob(**/*.jpg)于是连node_modules、.git、backup目录里的图片全被翻出来改了。这些目录里可能有几千张历史素材、别人给你的原始文件、甚至系统缓存图片一下子全被泼了一盆“统一命名”的冷水。我见过最离谱的一次一个人让AI整理桌面文件AI把.DS_Store这种系统隐藏文件也归入了“需要整理”的范围虽然没有重命名成功但日志里那一串操作看得人冷汗直冒。隐藏文件、符号链接、只读文件、系统文件、虚拟磁盘挂载点——这些都应该在批量改名之前被过滤掉或者至少单独列出来让你看一眼。所以我把“覆盖”拆成四层同名文件覆盖、进程占用覆盖、路径引用失效、范围失控。搞明白这四层下面的所有操作才有了理论依据。2. 动手之前用“预演”把改名做成可回滚操作2.1 干跑是什么为什么AI脚本默认就该干跑“干跑”Dry Run这个词来自运维和CI/CD领域意思是不真正执行操作只把“将要做什么”完整地打印出来供人审查。放到文件重命名场景下就是一个脚本跑完之后一份文件都没动只输出了类似这样的清单[DRY RUN] 将重命名: report_2023.xlsx - report_final.xlsx [DRY RUN] 将重命名: report_2024.xlsx - report_final.xlsx [DRY RUN] 冲突! report_final.xlsx 已存在, 已跳过 [DRY RUN] 共找到 25 个文件, 20 个将重命名, 3 个冲突, 2 个跳过我让AI生成所有批量改名脚本时第一条硬性要求就是脚本必须接受一个--dry-run参数默认值为True。也就是说不显式加--execute它永远只打印不执行。这个习惯救了我太多次。为什么干跑这么重要因为AI生成代码时它对“你的文件”的理解完全来自你的描述而你的描述通常是不完整的。你说“把所有jpg改成photo开头”AI不知道你有三个jpg已经叫photo_xxx了不知道有一个archive/photo_old.jpg不该动。干跑一次把完整清单摆出来人类扫一眼就能发现问题比事后恢复快一万倍。实际写代码时干跑的实现很简单import os from pathlib import Path def rename_files(dry_run: bool True): for f in Path(.).glob(*.jpg): new_name fphoto_{f.name} if f.name new_name: continue # 冲突检测 target f.with_name(new_name) if target.exists(): print(f[冲突] 跳过 {f.name} - {new_name} (目标已存在)) continue if dry_run: print(f[DRY RUN] {f.name} - {new_name}) else: f.rename(target) # 真正执行 print(f[执行] {f.name} - {new_name}) if __name__ __main__: import sys dry_run --execute not in sys.argv # 不带 --execute 一律干跑 rename_files(dry_run)这段代码简洁、直观、安全而且把最关键的两个点都做对了显式检查目标是否存在以及默认只打印不执行。2.2 三件套备份清单、改名日志、恢复脚本干跑只是第一步它解决了“看到”的问题但没解决“改坏了怎么回去”的问题。所以完整方案里我要求AI生成的不只是一个重命名脚本而是三样东西备份清单、改名日志、恢复脚本。所谓备份清单就是在执行前把所有将要改名的文件的原始信息记录下来包括完整路径、原名、新名、文件大小、修改时间甚至校验和用hashlib大文件可以只算前几MB的。这个清单本身就是一个CSV或JSON文件建议放在目标目录外面防止它也被打包改名。改名日志是执行过程中的实时记录每成功改一个文件就追加一行。这样如果跑到一半中断你能清楚知道改到哪了哪些成功哪些失败。恢复脚本则是根据备份清单自动生成的逆向脚本把“新名”改回“旧名”。严格来说它不需要AI写你自己用Python几行就能搞定但让AI一并生成的好处是它的逻辑和正向脚本一致不容易出现“正向用os.rename反向却用了不同API”这种不对称问题。// manifest.json 示例 [ { old_path: /home/user/photos/report_2023.xlsx, new_path: /home/user/photos/report_final.xlsx, size: 20480, mtime: 2024-03-01T10:00:00, sha256: a1b2c3... } ]恢复脚本读这个JSON逐条执行os.rename(new_path, old_path)。注意恢复之前要检查new_path还存在如果已经被人为删除或覆盖恢复脚本必须停下来报警而不是盲目创建空文件。这里再说一个小技巧如果文件量很大、价值很高我会要求AI先用zipfile或shutil.make_archive把整个目录压缩成带时间戳的快照再执行改名。压缩时用ZIP_DEFLATED大文件可以ZIP_BZIP2体积小一点。这个备份极其粗糙但极其有效改完了确认没问题再删掉压缩包。一句话备份是土办法但土办法永远有用。3. 核心实现AI提示词与Python脚本实战3.1 怎么写提示词AI才知道你要的就是安全和可回滚很多人让AI写脚本时提示词写的是“写一个Python脚本把当前目录下所有文件按日期重命名”然后AI就老老实实给出一个“一把梭”的版本。要避免这个结果提示词里必须把前两章的安全要求直接写进去。我一般用这样一套提示词模板大家可以直接抄帮我写一个Python脚本功能是批量重命名当前目录下的文件。 要求 1. 支持 --dry-run 和 --execute 两个模式默认 dry_run True 不带 --execute 参数时只打印将执行的改动不真正操作。 2. 重命名之前必须检查目标文件名是否已存在冲突时跳过并打印警告。 3. 重命名规则把文件按 XXX 规则修改这里写你的具体规则。 4. 排除以下目录/文件.git、node_modules、隐藏文件、备份目录。 5. 执行前生成 manifest.json记录原始路径、新路径、文件大小、修改时间 执行过程中把每步操作写入 rename.log。 6. 再生成一个 restore.py读取 manifest.json把文件恢复为原名。 7. 如果目录是 Git 仓库建议用 git mv 而不是 os.rename。 8. 打印统计结果共扫描到多少文件、重命名多少、跳过多少、冲突多少。 重命名规则是把所有 .txt 文件改成 日期_原文件名.txt日期取文件修改时间。前三个要求是安全底线最后一条是具体需求。你会发现AI很吃这一套给它的约束越明确它写出来的代码越接近生产级别。我之前试过只写“帮我改文件”AI给我的是一段10行代码没有任何冲突处理按上面的模板写AI直接生成一个带argparse参数解析、日志、JSON导出、恢复脚本、Git检测的完整工具。差别不是一星半点。3.2 脚本落地冲突检测与批量执行等AI生成完脚本别急着执行打开看一眼。重点看三个地方循环怎么写、冲突怎么判断、异常怎么处理。首先是循环。如果AI用os.listdir()然后自己拼路径容易在Windows下遇到反斜杠和正斜杠混用问题。我一般要求它用pathlib.Path跨平台干净利落。Path.glob()和Path.rglob()是兄弟俩前者不递归后者递归如果只想改当前目录千万记得用glob()否则又回到第1.4节说的“扩大打击范围”。其次是冲突判断。AI可能会写if os.path.exists(new_path): print(文件存在跳过)这个判断在大多数情况下够用但有一个死角大小写。如果你在macOS或Windows上把Report.txt改成report.txtos.path.exists()大概率返回True因为文件系统本身不区分大小写于是脚本认为“目标已存在”而跳过。反过来如果你用os.rename()强行改在macOS上它可能成功但行为取决于底层APFS配置有的机器上会创建出一个“看似同名但实际是新文件”的东西非常迷惑。Linux没有这个问题因为大小写敏感但这种平台差异恰恰是AI写代码时最容易忽略的。我之前处理这个问题是在脚本里加一个case_insensitive_fs()检测函数import tempfile, os def is_case_insensitive(path: str .) - bool: with tempfile.NamedTemporaryFile(dirpath, prefix.case_test_) as f: name f.name return os.path.exists(name.upper()) or os.path.exists(name.lower())把文件系统大小写敏感性测出来再决定冲突判断策略。这个细节99%的AI生成代码都不会替你考虑但实际工程里踩到就是个大坑。最后是异常处理。AI默认不写try...except因为“正常情况下”不会出问题。可真实环境下文件名可能包含非法字符Windows下不能有:/\|?*、路径可能超长Windows路径最大260个字符、文件可能正在被占用。我的习惯是要求每步操作都包一个try...except Exception as e失败时把错误信息连同文件路径写入rename_errors.log然后继续处理下一个文件。这样一次执行下来你能得到一份清晰的错误报告而不是脚本跑到一半戛然而止。3.3 批量重命名常见模式与对应代码聊完了“安全框架”再说说批量重命名本身。AI在规则生成上其实很擅长你把需求说清楚它能省你大量写正则的时间。常见的模式有四种序号填充模式例如把一堆照片改成IMG_001.jpg、IMG_002.jpg。这里有几个细节序号位数要固定不能1、2、10混排否则排序会乱建议至少两位数起步文件多了就三位。一个简单版本from pathlib import Path for i, f in enumerate(sorted(Path(.).glob(*.jpg)), 1): new_name fIMG_{i:03d}{f.suffix} print(f, -, new_name)日期前缀模式如果文件本身有修改时间可以在前缀里带上YYYYMMDDimport datetime for f in Path(.).glob(*.pdf): ts datetime.datetime.fromtimestamp(f.stat().st_mtime) prefix ts.strftime(%Y%m%d) new_name f{prefix}_{f.name} print(f, -, new_name)正则替换模式比如清理文件名里多余的空格、括号、版本号。AI很擅长这类活但你要在提示词里明确“保留扩展名不变”和“只替换匹配部分”import re for f in Path(.).iterdir(): if f.is_file(): stem, suffix f.stem, f.suffix stem re.sub(r\s, _, stem.strip()) new_name stem suffix print(f, -, new_name)Excel映射表模式如果你有一个Excel或CSV里面写着“旧名-新名”的对应关系可以让AI按表执行。这个模式的价值在于你不用在提示词里描述规则只需要先读映射表逐行检查两边都存在然后执行再记录日志。作为一个有经验的人我强烈建议你在批量重命名之前主动把“改完后的目录结构”打印出来看看。AI只会逐文件命名它不会告诉你“按照这个规则跑完之后三个月前的备份目录里会出现一批同名文件”。而人的眼睛是能看出这种问题的。 ## 4. 常见问题与避坑实录 ### 4.1 编码问题中文文件名在Windows上乱码到底是谁的锅 AI默认写Python都按UTF-8处理这在Linux和macOS上没问题Windows上的中文系统文件名则可能是GBK或系统本地代码页。不是说AI写错了而是它不知道你的系统默认编码和文件原编码可能不一致。 表现出的现象很典型脚本在Windows下跑打印出来的中文文件名全是乱码或者Path.glob()压根匹配不到中文开头的文件。解决办法不是让AI“用GBK”而是彻底绕开手写编码转换。 核心规则就一条**用pathlib处理路径不要自己拼字符串不要手动encode/decode文件名**。pathlib.Path在Windows上会使用系统API自动处理编码。如果你打印文件名时怕控制台乱码可以加一层兜底 python def safe_print(text: str) - None: print(text.encode(utf-8, errorsreplace).decode(utf-8, errorsreplace))更正经的办法是设置控制台编码Python 3.7 在Windows上可以用import sys sys.stdout.reconfigure(encodingutf-8, errorsreplace)另外有个隐藏坑文件名里的Unicode规范化。macOS用NFD分解Windows和Linux常用NFC组合同一个“e”带重音符号的文件名在不同系统上字节是不同的。如果你在两台机器间拷贝文件再从AI脚本里按名字判断很容易出现“看起来一样的文件名却匹配不到”。处理办法是统一规范化为NFCimport unicodedata def normalize_name(name: str) - str: return unicodedata.normalize(NFC, name)4.2 权限、占用与跨盘符问题批量改名不是每次都能成功失败原因千奇百怪但有一个共同特征AI的脚本不会告诉你“为什么失败”只会抛出一个异常然后整个进程挂掉。所以你必须预先给脚本打好“免疫针”。权限不足是最常见的一种。在Linux或macOS上你改一个只有root可写的文件时PermissionError就来了。在Windows上即使是普通管理员的窗口也可能因为UAC用户账户控制没有提权而失败。我的习惯是脚本先检测目录可写性用os.access(path, os.W_OK)不行就直接提示“请用管理员身份运行”而不是让你跑完了才发现30%文件因为权限没动。文件被占用在第一部分提过这里补充一个更隐蔽的场景杀毒软件或云盘客户端。它们会扫描并短暂锁定文件时机不定今天能跑通明天就卡住。应对方案是重试机制AI生成脚本时我会要求for attempt in range(3): try: f.rename(target) break except PermissionError: time.sleep(1 attempt) # 等1秒、2秒、4秒 else: log_error(f重试3次仍然失败: {f})跨盘符操作是另一个坑。如果原始路径和目标路径在不同磁盘/分区上os.rename()会直接报错OSError: Invalid cross-device link不是所有AI都会意识到这一点。这种情况应该改用shutil.move()它会自动复制删除。但这个复制过程不是原子的如果中途断电或进程被杀会出现“新文件没写完老文件已经被删”的情况所以跨盘符改名时务必要先走一遍备份三件套。以上问题我整理成一张速查表放到最后供参考现象常见原因解决思路中文文件名乱码/匹配不到系统编码不一致用pathlib设置utf-8输出统一Unicode规范化目标文件已存在冲突检测没做显式检查exists跳过或询问文件被占用Excel/Word/播放器开着文件关闭应用加重试机制权限不足系统文件或只读目录检测可写性管理员/root运行跨盘符报错原路径和目标路径不在同一磁盘用shutil.move代替os.rename大小写行为不一致文件系统差异检测大小写敏感性调整冲突逻辑隐藏文件/系统文件被改名glob范围太大排除.git、node_modules、隐藏文件、备份目录Git历史丢失直接用os.rename检测Git仓库改用git mv改到一半脚本崩了未做异常隔离每个文件单独try失败记日志继续跑恢复时目标已不存在恢复脚本直接执行恢复前检查存在性缺失要报警4.3 终极兜底把批量改名变成版本控制的一部分很多人觉得批量重命名是一次性操作改完就结束了。但站在长期维护的角度改名其实是版本控制的一部分。不管是Git仓库还是普通目录你最好在改名前让git status干净这样万一改出问题看一眼git diff就能评估影响范围。如果目录还不是Git仓库我的建议是先git init提交一次快照再执行改名。不用写项目说明不用定分支策略这个仓库的唯一作用就是给你一个廉价的“后悔药”。改完测试没问题再把这个临时仓库删掉或者保留下来做细微调整的对比。有人觉得这样太折腾可现实是AI生成的重命名规则往往不够完美你总要迭代一两次。第一次跑完发现某个子目录里的文件也被改了你没意识到第二次改了规则准备再来一次这时候如果没有基线版本你连“哪些文件已经被动过”都说不清。有了Git一切有迹可循。如果文件特大、目录特多、不适合Git那就退回到压缩包快照。便宜、无脑、可靠比任何高端的回滚机制都实在。5. 实操经验总结说点大实话我见过太多人拿着AI生成的脚本就往生产目录上跑跑完出了问题才来后悔。这个问题的本质不是“AI不行”而是我们人类自己把“审查”这一步跳过了。AI能做的是替你写代码、替你定规则但它没法替你理解“哪些文件不能动”。我自己的习惯已经固定下来了每次用AI做批量改名无论文件多寡都走四步先写清楚规则让AI生成带--dry-run的脚本然后跑一遍干跑把完整清单从头到尾过一遍再备份清单和日志必要时压缩快照整个目录最后才带--execute参数真正执行。这四步看起来繁琐但实际执行起来可能只需要三五分钟。你省下的这三五分钟代价可能是几百个文件的命名彻底乱掉以及后续无数个小时的整理时间。这笔账怎么算都划算。另外还有一个小技巧关于AI提示词的最后一条我总会加上“请解释你生成的代码在关键位置做了什么”这样AI会主动在冲突检测、恢复逻辑、异常处理旁边写注释。这些注释的质量有时候一般但它们能逼着我自己再看一遍代码很多因为“没细看”造成的低级错误就是在这个过程中被拦下来的。最后希望这篇东西能让你下次用AI批量改文件名的时候第一反应不是“跑起来看看”而是“先看看它准备覆盖谁”。这十个字我写在工位便签上贴了很久今天也送给你。
返回列表