rea:命令行与正则驱动的跨平台批量文件重命名与自动化归档工具

发布时间:2026/10/21 21:43:28
rea:命令行与正则驱动的跨平台批量文件重命名与自动化归档工具 前阵子整理下载目录我对着屏幕上密密麻麻的“新建文档(32).pdf”“图片_最终版3.png”“未命名222.txt”发了一会儿呆然后决定写一个叫rea的小工具来彻底解决这件事。rea的全称是 Rename Everything Automatically一个不依赖图形界面的批量文件重命名与归档工具核心能力就是一条命令把一组乱七八糟的文件名变成你真正想要的格式支持正则匹配、日期生成、序号填充、目录归档以及干跑预览和回滚日志。这篇文章适合谁看如果你经常处理素材整理、代码工程清库、下载目录打扫或者只是想给一批照片快速规范命名rea的思路和代码实现都能直接抄作业。我会从需求拆解、设计思路、完整实操到踩坑记录一条龙讲清楚尤其是那些在 macOS、Windows、Linux 上会微妙不同的细节全部摊开来说。1. 为什么做 rea从“手工整理”到“批量处理”的思维转变1.1 重新审视根本需求你到底是“整理文件”还是“整理规则”我先花了半小时梳理自己真正的痛点。看起来是“文件太多想要整理”但仔细一想手工整理之所以让人崩溃不是因为文件本身多而是因为每次整理都是重复劳动用同一种标准给文件改名同一个逻辑把文件挪进对应文件夹同样对重复二字头疼不已。所以核心需求不是“操作文件”而是“把操作规则固化下来让规则自动执行”。rea的定位由此确定做一个接受规则、执行规则的 CLI 工具不卷入图形界面的拖拽交互。为什么选 CLI因为在批量场景里图形界面反而低效。你要改一千个文件在文件管理器里一个个右键重命名肯定输给一条rea命令。而且 CLI 天然适合脚本化可以放进 cron 任务、CI 流程和自动化脚本这是图形工具做不到的。1.2 市面上的批量改名工具为什么不够用我试用过几款主流批量改名软件也经历过路径崩坏、正则支持残缺、重名覆盖无警告、以及改名后无法撤销的心惊胆战。它们的问题集中在三块第一正则引擎往往只支持简单通配符想在文件名里提取年份再重新组合成新格式操作起来非常费劲第二大部分工具没有“干跑预览”的习惯你只能先执行再后悔第三运行平台绑定严重Windows 端的工具在 macOS 上往往难以使用。作为经常在不同系统间切换的人我需要一个行为完全一致、基于文本配置、能进出任何脚本体系的工具。rea就是奔着这三个缺口去的正则完整支持、默认 dry-run 预览、跨平台运行。工具不在乎你文件在哪里它只负责把旧名变成新名并且保证变更可追溯。1.3 功能边界先做减法再做乘法任何一个工具都有失控的风险。我在规划rea时刻意圈定了几条功能边界第一它只处理文件和目录名不移动文件内容第二它不做内容批量替换那是另一个工具的事第三它不提供图形界面只提供清晰的命令行交互。这样做的好处是把出错概率压到最低把可测试性提到最高。边界明确后功能设计反而顺滑一个核心解析器处理命名规则一个执行器负责安全变更一个日志模块记录全部操作。你给它一个“目标模板”它返回一套“变更计划”确认后执行。整个过程可以像考卷一样反复演练这比任何花哨按钮都实在。2. 核心设计命名规则、安全机制与跨平台细节2.1 命名规则模板的设计原则rea的命名规则是我花最多心思的部分。它需要简单到一眼看懂又要强大到能处理复杂场景。最终我设计了一套由“原文件匹配表达式”和“目标文件名模板”组成的规则体系。原文件匹配表达式使用正则用来捕获你要提取的信息。比如原文件是IMG_20240105_153022.jpg你可以在表达式中定义四个分组拍摄设备、日期、时间、扩展名。如果正则写得清晰一组文件的所有关键信息都会进入捕获组。目标文件名模板中使用大括号加变量名的形式引用捕获组例如{year}-{month}-{day}_{shot_type}_{sequence}.{ext}模板支持内置变量。{year}、{month}、{day}从捕获或日期解析中获得{sequence}是自动递增序号{ext}是原文件扩展名。模板里还允许自由插入分隔符比如下划线、连字符、中括号。设计这套模板时我参考了常见日期格式化工具的思路但刻意用了大括号而不是百分号或反斜杠因为大括号在文件名中很少出现不会和用户原有的命名习惯冲突。每个变量还可以带参数比如{sequence:01}表示使用两位数字填充不足位置补零。2.2 安全第一dry-run、备份与回滚日志批量改名最可怕的不是改错而是改错之后没有回头路。一个不留神把2023_report.doc改成2023_report_1.doc结果又把另一个文件改成2023_report_1.doc那就是直接覆盖。为了防止这类事故我在rea里实现了一个强制安全的执行流程。第一步是 dry-run也就是“干跑”。执行任何变更前工具只读取文件列表、计算新文件名、输出计划表但不写盘。用户看到计划后确认无误再执行。这个习惯一开始我也有点嫌麻烦实操下来发现干跑多花的时间远低于出错之后恢复的时间。第二步是写入变更日志。每次实际执行rea会按时间戳生成一份 JSON 日志文件里面记录每一项操作前后的完整路径。日志默认存放在用户指定的日志目录且日志本身不会被批量改名规则触及避免日志文件也被卷进变更。第三步是备份机制。默认情况下rea不会执行不可逆操作。它推荐用户使用--backup参数执行前把所有待变更文件复制到一个临时隐藏目录。虽然备份会占用额外磁盘空间但在批量处理重要资料时这个成本绝对值得。2.3 跨平台要处理的三个细节跨平台是这个工具最隐蔽的挑战。我第一版写完在 macOS 上跑得很溜拿到 Windows 上就翻车了问题出在三个细节上。第一个是路径分隔符。Windows 使用反斜杠类 Unix 使用正斜杠。rea内部统一用 Node.js 的path模块处理路径避免手写字符串拼接在输出日志和预览表时再转换成各平台习惯的展示格式。第二个是文件名大小写。Windows 文件系统默认大小写不敏感但 Linux 敏感。你要把一个文件从Readme.txt改成README.txt在 Linux 上很容易在 Windows 上如果只改大小写系统会认为源和目标完全相同直接报错或静默失败。解决方案是两步改名先把目标改成临时临时文件名再把临时名改成最终目标名。第三个是文件被占用。Windows 下文件一旦被某个进程打开rename 操作就会抛EPERM或EBUSY。程序不能盲目失败退出而应该识别这类场景并明确提示占用者甚至等待重试。类 Unix 系统上文件被打开也能重命名但为了行为一致rea的默认策略仍是检测后警告。3. 实操实录从零搭建 rea 的过程3.1 项目初始化与环境选型我选择 Node.js 来实现rea原因有三跨平台支持最好文件系统 API 成熟包管理生态完善后续想加语法高亮、表格输出等都有现成方案。初始化时我只依赖一个辅助库用于命令行参数解析核心逻辑全部手写保持代码透明可审查。先建立项目目录用npm init初始化然后创建一个cli.js入口mkdir rea cd rea npm init -y在入口文件顶部定义命令参数解析支持以下几个核心参数--match 必填用于匹配原文件名的正则表达式 --template 必填目标文件名模板 --base 可选操作的基础目录默认当前目录 --ext 可选限定参与处理的扩展名列表 --dry-run 执行干跑预览 --backup 执行前备份 --log-dir 日志目录参数解析没有采用复杂方案就是逐项读取process.argv然后组装成配置对象。参数名刻意设计得短而明确方便在 cron 任务里一行写完。3.2 核心代码实现解析、匹配、生成、执行整个rea的单次运行可以拆成四个阶段扫描文件、匹配旧名、计算新名、提交变更。扫描阶段使用递归方式读取目录但不读取符号链接指向的目录避免循环。每一级的目录可以被当作“只读目录”过滤也可以被当作“待改名对象”这取决于匹配规则是否命中。我在设计时有意让目录名也可以参与改名这样整理项目树时会非常方便。匹配阶段用用户提供的正则表达式逐一测试文件名例如const regex new RegExp(matchPattern, i); const parts regex.exec(filename); if (!parts) return null;注意这里我用i作为默认选项不实际运行时我会让用户决定是否忽略大小写默认不忽略否则大小写敏感的场景会被误伤。但为了更安全我额外允许用户在--match参数中以/i标记结尾来显式不区分大小写。计算新名阶段将捕获组映射到模板变量处理内置函数。核心逻辑大约如下function renderTemplate(template, matches, index) { return template.replace(/\{(\w)(?::([^}]))?\}/g, (raw, name, opt) { if (!builtins[name]) return raw; return builtins[name](matches, index, opt); }); }内置变量里的{sequence}比较特殊它的值依赖文件排序。所以我先扫描全部文件再按某种策略排序最后才对每个文件渲染模板确保序号按预期递增。提交变更阶段每一条记录先写入日志再执行 rename。顺序是先写日志后改名这样万一程序中途崩溃日志里至少记录了已经执行的所有操作可以用来恢复。3.3 案例一把相机照片改成“日期_位置_序号”格式假设我有一个photos目录里面全是相机导出的文件命名类似IMG_20240105_153022.jpg、IMG_20240105_153738.jpg。我想把文件名改成“位置描述_日期_序号”但日期格式要从20240105拆成2024-01-05。匹配表达式可以写成^IMG_(\d{4})(\d{2})(\d{2})_(\d{6})\.([a-zA-Z0-9])$目标模板vacation_{year}-{month}-{day}_{sequence:02}.{ext}在执行前先用--dry-run看预览node cli.js --base ./photos --match ^IMG_(\d{4})(\d{2})(\d{2})_(\d{6})\.([a-zA-Z0-9])$ \ --template vacation_{year}-{month}-{day}_{sequence:02}.{ext} --dry-run输出会显示一个变更计划表例如IMG_20240105_153022.jpg - vacation_2024-01-05_01.jpg IMG_20240105_153738.jpg - vacation_2024-01-05_02.jpg注意这个案例里文件名顺序并不等于时间顺序如果照片是连拍的序号意义不大更好的做法是按拍摄时间排序再编号。我在扫描阶段支持--sort-by mtime这样序号能反映文件的修改时间先后。对这个案例我会先按 mtime 排序再渲染模板。确认干跑结果无误后去掉--dry-run并加上--backup执行node cli.js --base ./photos \ --match ^IMG_(\d{4})(\d{2})(\d{2})_(\d{6})\.([a-zA-Z0-9])$ \ --template vacation_{year}-{month}-{day}_{sequence:02}.{ext} \ --sort-by mtime --backup执行完成后目录里会出现一个隐藏备份目录记录这次操作涉及的全部原文件。如果后续发现新的需求可以恢复原状重新处理。3.4 案例二代码工程目录的统一归档第二个案例来自项目工程。一个模拟项目X的docs目录里有各种命名混乱的文档例如final report.txt、Draft_03.txt、notes_2023-12-30.txt我想统一成“项目缩写_类型_日期_版本”的格式。对不同规则文件一个正则很难全覆盖。rea的设计里支持多个规则依次尝试命中即生效。我先为两类文件分别定义规则第一类文档文件匹配表达式^(final|draft|notes)[_\s-](.)\.txt$模板prj_{doc_type}_{date:today}_{sequence:02}.txt第二类图片素材文件匹配表达式^(scan|photo)_(\d{8})\.(.)$模板prj_image_{year}-{month}-{day}_{sequence:02}.{ext}{date:today}是我内置的另一个特殊变量允许在无法从原文件提取日期时使用当天日期填充。这个变量在批量归档当天收到的文件时非常有用。实际执行时rea会先加载一个规则文件而不是命令行参数这样保持命令短小也便于把规则版本化纳入代码仓库管理。执行后我还会生成一份manifest.json记录每个文件从哪个路径变成了哪个路径方便后期追溯。我的建议是不要只把这个日志放在本地请同步到一个私有仓库里文件变更的时间点和规则版本都能对应上排错时帮助很大。4. 常见问题与排查技巧实录4.1 正则匹配正常但捕获组总是为空这个问题第一次出现时我以为是正则写错了。反复调试后发现问题出在可选分组上。比如我的正则写成^IMG[_-]?(\d{4})?(\d{2})?当文件名没有分隔线时捕获组的顺序会整体错位{year}捕获到空值。解决原则很简单正则里的每个捕获组都要固定存在如果可能缺失要用占位符而非让组本身可选项或者在渲染模板前对捕获组做一次校验缺字段就报错并给出文件名。宁可报错也不要生成一堆空字段文件。4.2 改名后文件名冲突导致覆盖批量改名的经典事故就是目标名撞车。比如所有文件都改成report_{sequence}.pdf但排序顺序不稳定序号分配就会和预期不一致。更严重的情况是某些文件根本不应该参与改名但因为模板生成的新名恰好与另一个文件重名导致冲突。rea在处理冲突时默认不覆盖已存在同名文件而是把整个冲突项标记为错误并在预览中高亮。我测试过是否要自动追加后缀最后放弃了工具自动加后缀虽然不覆盖文件但会让用户失去命名控制权宁可提示、重跑、重新制定规则也不能静默地把事情“变得差不多”。4.3 Linux 下中文文件名乱码在类 Unix 系统上文件名本质上是字节序列不一定是合法的 UTF-8。如果你从 Windows 拷贝一批旧文件过来文件名可能带着非 UTF-8 编码Node.js 默认按 UTF-8 解析就会变成乱码。我在处理时添加了检测逻辑如果文件名解码成 UTF-8 时出现 replacement 字符就保留原始字节不做解析并在日志里警告。rea的默认策略是宁可跳过也不进行破坏性修改。后来的实践也证明这个策略是对的因为你无法从乱码文件名中可靠地推断原始内容还是让用户手工处理这些异常文件更稳妥。4.4 Windows 下只改大小写失败前面提到过Windows 对大小写不敏感。实际测试中把readme.txt改成README.txt如果直接执行fs.rename绝大多数情况下什么都不发生甚至不会报错。因为系统认为这是同一个文件。解决方案是要么故意先改到一个中间名再改到最终名要么使用 Windows 底层特有方式处理。rea的实现就是在检测到“目标与原文件名只有大小写差异”时自动插入一次临时改名。这个临时名规则是在原文件名后加随机短串比如readme.txt.tmp_8f3a然后再改成最终目标。4.5 日志滚不回来怎么办执行一次大变更之后最怕两件事一是担心结果不对二是想恢复原样。我的日志设计里包含旧路径和新路径理论上可以反向把新路径恢复成旧路径。但有个前提你不能再执行任何新的批量改名否则会乱。实际操作中我建议使用 git 管理文件目录的元数据很不现实因为文件太普通了。更实用的恢复方式是利用 backup 目录。执行前备份的文件放在原目录结构外恢复时直接整体覆盖回来。如果没加备份参数那就只能逐条用日志恢复这时日志的完整性非常重要。所以我的自我要求是每次执行必须看到日志成功写入后才允许工具继续日志写入失败改名流程立刻中止。5. 让 rea 变得更顺手几个扩展方向5.1 接入定时任务实现目录自动归档定时任务是我用得最多的扩展场景。下载目录每隔三天就会重新堆积我写了一条 cron 任务每周日凌晨用rea把下载目录里超过七天的文件归档到对应月份目录。命令长一点没关系因为全部参数写在规则文件里cron 只调用一条简单命令。这个过程里验证过的关键心得是定时任务环境下一定要保留 dry-run 的阶段日志不能只输出“成功”。否则哪天规则写错了图片被错误命名你根本意识不到。我会把每次执行产生的 preview 计划输出重定向到日志文件保留一个月。5.2 与文件标签系统结合单纯的改名解决不了一件事语义检索。文件名能承载的信息有限更好的方案是把命名生成的元数据写入一个索引表。我基于rea的 manifest.json 做了一个简单的本地索引通过文件名直接反查出文件来源和归属项目。这样即使文件挪了位置索引依然准确。其实工具本身要保持克制不去强制生成某种数据库因为文件的组织方式带着强烈的个人习惯。能输出稳定数据格式的底层工具比什么都管的大一统工具好维护得多。5.3 把常用命名规则沉淀成模板库我用了一阵子后发现很多命名规则高度重复。比如“日期描述序号”在照片处理、日志归档、项目文档里反复出现。于是我把常用规则整理成模板库用rea --from-template photo直接生成对应参数再按需微调。模板库的格式就是一份 JSON 文件其中包含正则、模板、排序方式和冲突策略。这样做的好处是团队内部可以共享规范新人拿到一条命令就能批量整理文件不用理解正则细节。6. 我对 rea 的真实使用体会我现在几乎每周都会用到rea但最常使用的场景反而没那么“高级”给老婆的旅行照片改名、给孩子的作业电子版归档、给横跨三年的项目资料统一前缀。工具只有进入日常才不会被遗忘这也是我始终坚持默认干跑、坚持完整日志的原因。批量改名本质上是高风险低容错的操作工具设计得再聪明都不能替代一双事后能回看过去的眼睛。最后再分享一个小技巧复杂场景不要试图写一个万能规则先用--dry-run处理一个子目录校验结果显示在预览列表里的每一条记录再用规则文件固化版本。宁可多花三分钟检查预览也绝对不要直接在正式目录上试错。这大概就是我踩过最多次的坑也是rea在一次次操作里真正沉淀下来、值得你抄走的核心经验。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询