先确认rename版本:运行rename -v,输出含perl为perl版(支持正则),含util-linux为c版(仅字面替换);perl版需转义特殊字符、用-n预览,c版语法为rename .old .new *.old。

rename 命令不是万能的,它在不同系统上可能是两个完全不同的程序,直接套用教程命令大概率报错。先确认你手里的 rename 是哪个版本,再决定怎么写参数。
怎么判断当前系统用的是 Perl 版还是 util-linux 版 rename
运行 rename -V 或 rename --version:
– 如果输出含 perl、Perl Programmers Reference Guide,就是 Perl 版,支持正则;
– 如果输出是类似 v2.34、util-linux,就是 C 语言版,只做字面替换。
别跳过这步——很多“rename 's/\.txt$/.log/' *.txt 报错 invalid option -- 's'”的问题,就卡在这儿。
Perl 版 rename 的安全写法和常见坑
Perl 版功能强,但正则写错或路径没匹配上,会静默失败或误改名:
– 所有特殊字符(点、括号、美元符等)必须转义,比如后缀匹配要写 \.txt$,不是 .txt$;
– 用 -n 参数预览:执行 rename -n 's/\.txt$/.log/' *.txt,它只打印将要做的操作,不真正执行;
– 捕获组编号从 开始,不是 #1(那是 mmv 的语法);
– 文件名含空格、括号、中文时,shell 通配符 *.txt 可能不匹配,建议先用 ls *.txt | head -5 确认实际有哪些文件。
不用 rename 也能批量重命名:for + mv 的硬核细节
这是最通用的方式,所有 Linux 都带,但新手常栽在几个细节上:
– 必须用双引号包裹变量:"$file",否则含空格的 my photo.jpg 会被拆成两个参数;
– 通配符没匹配到任何文件时,*.txt 会原样传给 for,导致创建名为 *.txt 的错误文件,加一句 shopt -s nullglob 可避免;
– 修改数字序号时,原始字符串长度不等于新编号位数,比如 img1.jpg → img2.jpg 没问题,但 img001.jpg → img2.jpg 会破坏排序,补零得显式用 printf "%03d";
– 别在循环里边改边读同一通配符:for f in *.jpg; do mv "$f" "$(echo "$f" | sed 's/old/new/')"; done,如果新名又匹配 *.jpg,可能被重复处理。
什么时候该换 mmv 而不是硬刚 rename 或 for
mmv 不是替代品,是另一类问题的解法——当你面对的是结构清晰、有固定分段的文件名时:
– 比如 report_Q1_2023.pdf、report_Q2_2023.pdf,想改成 2023_Q1_report.pdf,用 mmv 'report_Q?_*.pdf' '#2_#1_report.pdf' 一行搞定;
– 它天然防错:如果匹配不到源文件,直接报错退出,不会静默跳过;
– #1、#2 引用的是通配符位置,不是正则捕获组,逻辑更直觉,也更容易写对;
– 缺点是得单独安装(sudo apt install mmv),且不支持递归或条件判断。
真实场景里,没有“最好”的工具,只有“最不容易出错”的组合。一个稳妥的操作链通常是:ls 看文件 → rename -n 或 echo mv 预览 → 小范围实操验证 → 再全量执行。最容易被忽略的,其实是通配符在空目录下的行为,以及文件名中不可见字符(比如 Unicode 零宽空格)带来的匹配失效。











