如何使用Bash递归批量重命名文件 替换路径中所有匹配字符串
Bash递归全局重命名实现方案
两个问题的根因很明确:
- 遍历顺序错误:如果先处理上层目录,改名后下层路径的前缀就失效了,必须从最深层的节点开始向上处理
- 依赖
rename的实现差异:不同发行版的rename分util-linux版和perl版,语法不统一,且默认匹配规则不灵活,完全可以用Bash内置能力替代。
可直接使用的脚本
#!/bin/bash set -euo pipefail # 参数校验 if [ $# -ne 3 ]; then echo "调用方式: $0 <目标根目录> <待替换字符串> <替换为的字符串>" exit 1 fi ROOT=$1 OLD_STR=$2 NEW_STR=$3 if [ ! -d "$ROOT" ]; then echo "错误:目录 $ROOT 不存在" exit 1 fi # 核心:-depth 参数让find先输出目录内的所有子项,最后输出目录自身,从深到浅处理避免路径失效 find "$ROOT" -depth -name "*$OLD_STR*" | while IFS= read -r path; do parent=$(dirname -- "$path") old_name=$(basename -- "$path") # Bash内置全局替换语法:// 表示替换所有匹配片段,一次替换完所有出现位置 new_name=${old_name//"$OLD_STR"/"$NEW_STR"} [ "$old_name" = "$new_name" ] && continue new_path="$parent/$new_name" if [ -e "$new_path" ]; then echo "跳过 $path:目标路径 $new_path 已存在" continue fi mv -v -- "$path" "$new_path" done
关键逻辑说明
- 解决目录改名导致路径失效:
find的-depth参数会自动调整遍历顺序,所有子文件、子目录都会在其父目录之前完成重命名,处理父目录时已经不需要再访问它下面的任何内容,完全不会出现找不到路径的错误。 - 解决单次仅替换首个匹配的问题:使用Bash原生参数扩展
${var//old/new}做字符串替换,不需要依赖外部rename命令,默认就会替换目标字符串里所有匹配的片段,不需要重复执行命令,性能也更高。 - 兼容性:不依赖任何发行版特有的命令参数,只要是Bash 3.0以上版本都能正常运行,适配绝大多数Linux、macOS环境。
使用示例
针对给出的测试目录结构,给脚本加执行权限后在当前目录执行:
chmod +x recursive_rename.sh ./recursive_rename.sh . "pattern" "expression"
执行完成后就能得到预期的重命名结果,不会抛出路径不存在的报错,所有文件名、目录名中出现的pattern不管有多少处都会被一次性替换为expression。
如果需要支持正则匹配替换,只需要把
new_name=${old_name//"$OLD_STR"/"$NEW_STR"}替换为new_name=$(sed "s/$OLD_STR/$NEW_STR/g" <<< "$old_name")即可,此时传入的待匹配字符串支持标准正则语法。
内容的提问来源于stack exchange,提问作者jthulhu
相关产品推荐
相关产品推荐

