优先用Perl版rename,需先运行rename --version确认:含perl或File::Rename为Perl版(支持正则、-n预览),含util-linux为GNU版(仅字面替换、无-n);错用会导致file.old.txt误改为file.new.txt。

能批量改后缀,但必须先确认你用的是哪个 rename 版本——用错会把 file.old.txt 改成 file.new.txt,而不是只动结尾。
怎么判断自己用的是 Perl 版还是 util-linux 版 rename
运行 rename --version:
- 输出含
perl或File::Rename→ 是 Perl 版(支持正则、安全) - 输出含
util-linux→ 是 GNU 版(只做字面替换,不认$,也不支持-n预览)
Ubuntu/Debian 默认装 Perl 版;CentOS/RHEL 8+ 默认是 util-linux 版,且没装 Perl 版——这是批量改后缀失败最常踩的坑。
用 Perl 版 rename 安全改后缀
它靠正则锚定结尾,不会误碰文件名里的相同字符串:
- 预览将要改哪些:
rename -n 's/\.txt$/.md/' *.txt - 真正执行:
rename 's/\.txt$/.md/' *.txt - 单引号必须,否则 shell 会提前展开
$ - 如果通配符没匹配到文件,命令会报错,不会静默跳过
注意:通配符 *.txt 不进子目录;要递归处理,得配合 find:find . -type f -name "*.txt" -exec rename -n 's/\.txt$/.md/' {} +
不用 rename 时,for + mv 是最稳的备选
兼容所有 shell(bash/zsh/dash),不依赖外部命令,也绕开了版本混乱问题:
- 基本写法:
for file in *.txt; do mv "$file" "${file%.txt}.md"; done -
${file%.txt}是 Bash 参数扩展,只删结尾的.txt,比sed轻量 - 双引号包裹
"$file"和"${file%.txt}.md",防空格、中文、括号出错 - 若当前目录没有
.txt文件,*.txt会原样传给for,导致尝试重命名字面量*.txt—— 加上shopt -s nullglob可避免
别跳过测试:找一个含空格的文件(如 my report.txt),先手动跑一遍 echo mv "$file" "${file%.txt}.md" 看输出是否符合预期。
为什么 util-linux 版 rename 很容易翻车
它不区分“后缀”和“字符串”,只做全局字面替换:
- 命令
rename .txt .md *.txt会把config.txt.bak改成config.md.bak,也会把notes_old.txt改成notes_old.md—— 这没问题;但若文件叫log.txt.backup,就会变成log.md.backup,这不是改后缀,是误替换 - 它没有
-n选项,无法预览,改完才发现错了,只能靠备份回滚 - 参数顺序固定:第一个是“被替换字符串”,第二个是“替换成的字符串”,第三个才是文件列表 —— 记混就直接报错
真正麻烦的不是语法本身,而是你永远没法 100% 确保目标目录里没有其他 .txt 字符串混在文件名中间。只要存在这种风险,for + mv 就比 util-linux 版 rename 更值得信赖。


















