perl版rename支持正则表达式,需用锚点$和转义.确保精准替换扩展名,捕获组可重排文件名结构,递归处理须配合find,且无撤销机制需提前备份。

确认你用的是 Perl 版 rename
执行 rename -V 或 man rename:如果输出含 Perl expression 或类似 rename [ -v ] [ -n ] [ -f ] perlexpr [ files ],就是你要的 Perl 版;如果显示 rename from util-linux 或版本号像 2.39,那是 C 版,只支持 rename .old .new *.old 这种简单替换,不能处理正则,别用。Ubuntu/Debian 默认对;CentOS 7 需先装 sudo yum install prename;RHEL 8+ 已默认 Perl 版。
改扩展名必须加锚点 $ 和转义 \.
常见错误:rename 's/.txt/.log/' *.txt —— 它会把 notes.txt.bak 改成 notes.log.bak,因为 .txt 匹配任意位置。正确写法是:rename 's/\.txt$/.log/' *.txt。\. 转义点号,避免匹配任意字符;$ 锚定行尾,确保只替换真正的扩展名;单引号包裹整个表达式,防止 shell 提前解析 $ 或 *。
匹配并重排结构化文件名(如 2024-北京-001.txt → 北京-24-001_Good.txt)
这类操作靠捕获组实现,不用写循环。例如:
rename 's/(\d{4})-(.*)-(\d{3})\.txt$/$2-$1-$3_Good.txt/' *.txt
说明:
-
(\d{4})捕获年份(如2024),对应$1 -
(.*)捕获中间部分(如北京),对应$2 -
(\d{3})捕获编号(如001),对应$3 - 替换模板中可自由拼接、加字、改大小写,比如
$2-$(printf "%02d" $1 | cut -c3-)要求额外用e修饰符(rename 's/.../.../e'),但多数场景直接字符串拼接更稳
递归处理子目录必须用 find,不能只靠 *
rename 默认只作用于当前目录,rename 's/.log/.out/' *.log 对 ./sub/file.log 完全无效。安全递归写法:
find . -name "*.log" -exec rename 's/\.log$/.out/' {} \;
注意:{} 和 \; 之间必须有空格;\; 是 find 的终止符。如果系统里 rename 不接受路径参数(极少见),改用 find . -name "*.log" -print0 | xargs -0 -I {} bash -c 'mv "$1" "$(dirname "$1")/$(basename "$1" .log)_archive.log"' _ {}。真正容易被忽略的点是:rename 不提供撤销机制,出错只能靠备份;文件名含中文、空格、括号时,Perl 版 rename 本身能处理,不用额外加引号或 -print0,但 find 配合 mv 时必须用 -print0 | xargs -0。











