<p>优先用 Perl 版 rename,需先运行 rename -V 确认版本:含“Perl”为支持正则的 Perl 版,否则为仅字面替换的 C 版;误用会导致 invalid option -- 's' 等错误。</p>

直接说结论:优先用 rename,但必须先确认它是 Perl 版;不是就别硬套正则,否则报 invalid option -- 's' 这类错。
怎么判断你手里的 rename 是哪个版本
运行 rename -V 或 rename --version:
- 输出含
perl、Perl Programmers Reference Guide→ Perl 版,支持正则,语法如rename 's/\.txt$/.log/' *.txt - 输出是
v2.34、util-linux→ C 版,只做字面替换,语法是rename .old .new *.old
别跳过这步——很多“命令执行失败”其实只是版本不匹配。C 版本在 CentOS/RHEL 默认安装,Ubuntu/Debian 默认是 Perl 版,但装过 util-linux 更新后可能被覆盖。
Perl 版 rename 的安全写法和典型错误
它功能强,但写错正则或没预览,会静默改错、覆盖甚至删文件:
- 所有特殊字符必须转义:
\.匹配点号,\$匹配字面美元符,^和$要锚定位置,否则s/LOG/log/可能把DEBUG.LOG改成DEBUG.log - 执行前必加
-n预览:rename -n 's/^IMG_(\d+)\.jpg$/img_$1.png/' IMG_*.jpg,只打印动作,不真正改 - 通配符要引起来或确保已展开:
*.jpg在无匹配时会原样传入,导致操作名为*.jpg的文件;建议先ls IMG_*.jpg | head -3确认实际匹配项 - 捕获组用
$1、$2,不是#1(那是mmv的语法)
没 rename 或不能用正则时,for + mv 怎么写才不崩
这是 100% 兼容的 fallback 方案,但空格、中文、无匹配文件这三件事最容易翻车:
- 变量永远加双引号:
"$f",否则my photo.jpg会被拆成my和photo.jpg两个参数 - 避免
for f in `ls *.log`——ls输出按换行分割不可靠,含空格文件名会断裂;改用for f in *.log; do [ -e "$f" ] && ... - 无匹配时
*.log会字面传入,导致创建名为*.log的文件;加shopt -s nullglob开启空匹配跳过,或开头加ls *.log >/dev/null 2>&1 || exit - 需要补零编号时,显式用
printf "%03d":mv "$f" "img$(printf "%03d" $i).jpg",别依赖原始文件名长度
处理中文、括号、空格文件名的底线原则
这类文件名本身没问题,崩掉是因为 shell 分词逻辑被破坏:
- 不用
ls | while read,换行符不是文件名分隔符;改用find -print0 | xargs -0或while IFS= read -r -d '' -
basename对路径安全,但别在命令替换里嵌套未引号的$(ls *.log)—— 它会触发 word-split,彻底乱序 - 目标名可能冲突?加
mv -i交互确认,或先echo "$new_name"检查是否重复 - 终端 locale 和文件系统编码不一致(比如
LANG=C但文件名是 UTF-8),rename 可能截断字节 → 先设export LANG=en_US.UTF-8,或用convmv转码
真正麻烦的不是“哪条命令能跑通”,而是当前 shell 是否展开通配符、rename 版本是否匹配、目标名是否存在冲突——这些没法靠背命令解决,得靠 echo、ls、rename -n 逐层验证。


















