最直接方法是for循环配合mv,但需用"$file"防空格错误、先echo预览;rename命令有Perl版(支持正则)和util-linux版(仅字符串替换)之分,需用rename -V判断。

用 for 循环配合 mv 最直接,但后缀名容易出错
Linux 下批量重命名没内置“重命名所有 .txt 为 .log”的命令,得靠组合。最常用的是 for + mv,但新手常卡在变量扩展和通配符匹配上。
常见错误现象:mv: target 'xxx.log' is not a directory——其实是把整个列表当成了单个文件名;或者重命名后文件全堆在一行、空格被截断。
- 确保用双引号包裹变量:
"$file",否则含空格的文件名会崩 - 别直接写
for file in *.txt然后mv $file ${file%.txt}.log,万一没匹配到任何.txt文件,for会拿字面量*.txt当文件名去试,导致创建错误文件 - 先加
echo预览:echo mv "$file" "${file%.txt}.log",确认输出无误再删掉echo执行
rename 命令快,但 Perl 版和 util-linux 版不兼容
很多教程说 rename 一行搞定,但实际你装的可能是两个完全不同的程序:Perl 写的(常见于 Debian/Ubuntu)或 C 写的(常见于 CentOS/RHEL)。它们参数格式相反,混用必报错。
判断方法:运行 rename -V。输出含 perl 就是 Perl 版;输出是版本号如 v1.3 就是 util-linux 版。
- Perl 版(推荐):
rename 's/\.txt$/.log/' *.txt—— 支持正则,灵活 - util-linux 版:
rename .txt .log *.txt—— 只能字符串替换,且要求旧后缀必须存在,不能写正则 - 如果
rename报invalid option -- 's',说明你有 util-linux 版,却用了 Perl 语法
处理带序号的文件(如 photo_001.jpg → photo_002.jpg)要小心数字截断
想给一批文件统一加偏移(比如全部序号 +1),容易用 $((...)) 算术扩展,但默认不补零,001 变成 2,排序就乱了。
使用场景:整理相机导出的照片、日志轮转后的归档。
- 提取数字部分建议用
grep -oE '[0-9]+'或 Bash 的${file##*_}(假设下划线分隔) - 补零必须显式做:
printf "%03d" $((num + 1)),不能依赖原始字符串长度 - 别在循环里边改边读:
for f in *.jpg; do mv "$f" "$(printf ...).jpg"; done—— 如果新名又匹配上*.jpg,后续迭代可能重复处理
跨目录移动+重命名时,mv 的路径解析优先级容易被忽略
执行类似 mv dir1/file.txt dir2/newname.txt 是移动并改名,但如果你写成 mv dir1/*.txt dir2/,而 dir2/ 不存在,mv 会把所有文件“重命名”成 dir2 这一个名字(最后一个覆盖前一个),而不是报错。
这种行为在脚本里极难排查,尤其当 dir2 是变量拼出来的路径。
- 执行前先用
[ -d "dir2" ]检查目标目录是否存在 - 如果目标路径含变量,务必用
"$target_dir"包裹,避免空变量导致mv *.txt变成当前目录覆盖操作 -
mv -v开启详细模式,至少能看到每步实际操作对象
实际批量改名最麻烦的不是语法,是预判文件名里有没有换行、控制字符、不可见 Unicode —— 这些会让几乎所有基于空格或换行分割的循环失效。真遇到,得切到 find -print0 | xargs -0 那套逻辑。










