Debian 环境下实现特定文件名调整规则的批量重命名脚本求助
Shell批量剧集重命名脚本开发问题
场景与目标
开发Shell自动化脚本,对指定目录树内的剧集文件按统一规则批量重命名,适配Kodi媒体刮削工具的剧集识别逻辑,支撑新文件入库时的自动归档流程。
约定重命名规则
- 规则1:移除文件名中所有
S00-S99范围的季数标识,匹配逻辑为s/[sS](0[1-9]|[1-9][0-9])/ - 规则2:为文件名中独立存在的两位数字补充
E前缀,匹配逻辑为识别文本边界内的两位数字/\b([0-9]{2})\b/,替换为E+匹配内容
规则转换示例
三类格式不一致的源文件,统一转换为Kodi可识别的标准格式:
| 源文件路径片段 | 转换后目标路径片段 |
|---|---|
[lorem ipsum] dolor sit amet 07 [consetetur][1080p].mkv | [lorem ipsum] dolor sit amet E07 [consetetur][1080p].mkv |
[lorem ipsum] dolor sit amet S04 07 [consetetur][1080p].mkv | [lorem ipsum] dolor sit amet E07 [consetetur][1080p].mkv |
[lorem ipsum] dolor sit amet S04 E07 [consetetur][1080p].mkv | [lorem ipsum] dolor sit amet E07 [consetetur][1080p].mkv |
现有问题脚本与报错
因不熟悉Shell环境下的正则嵌入逻辑,基于旧脚本框架修改后写出的代码如下:
#!/bin/bash start_dir="//srv/MEDIA2/" find "$start_dir" -name '*.*' -type f \ |sort \ |while read name; do ((i++)) mv -i "$name" \ #remove season part "$(printf 's/[sS](0[1-9]|[1-9][0-9])/ "$(dirname "$name")" $((i)) "$(basename "$name")")" #prepend E to free standing double digits "$(printf 's/\b([0-9]{2})\b/' "$(dirname "$name")" $((i)) "$(basename "$name")")" done
脚本运行时返回如下错误:
//home/user/./rnscript.sh: line 14: s/[sS](0[1-9]|[1-9][0-9])/: No such file or directory //home/user/./rnscript.sh: line 16: s([0-9]{2}/: No such file or directory
报错根因
mv命令需要传入明确的目标文件路径作为第二个参数,脚本直接把正则替换表达式写在printf的格式串位置,没有将正则逻辑作用于实际文件名,导致Shell把正则表达式本身当成待执行的路径,触发“文件不存在”的报错- 脚本未衔接两步替换的上下文:移除季数标识的输出,需要作为下一步“给独立两位数字加E前缀”的输入,而不是把两个正则表达式当成两个独立的
mv目标参数 - 原有路径读取逻辑未处理带空格、特殊字符的文件名,遍历过程中会出现路径拆分错误
- 路径配置存在冗余双斜杠问题
修正后的可用脚本
#!/bin/bash # 配置待扫描的媒体根目录 start_dir="/srv/MEDIA2/" # 以空字符为分隔符遍历文件,兼容带特殊字符、空格的文件名 find "$start_dir" -name '*.*' -type f -print0 \ | sort -z \ | while IFS= read -r -d '' full_path; do # 拆分文件所属目录、文件名、扩展名 file_dir=$(dirname "$full_path") file_base=$(basename "$full_path") file_name="${file_base%.*}" file_ext="${file_base##*.}" # 第一步:移除所有S/s开头的两位季数标识,同时清理替换后产生的多余空格 new_name=$(printf '%s' "$file_name" \ | sed -E 's/[sS](0[1-9]|[1-9][0-9])//g' \ | sed -E 's/\s+/ /g; s/^ | $//g' ) # 第二步:给独立存在的两位数字添加E前缀,跳过已经带E的集数避免重复匹配 new_name=$(printf '%s' "$new_name" \ | sed -E 's/\b([0-9]{2})\b/E\1/g' ) # 拼接完整新文件路径,路径无变化则跳过 new_full_path="${file_dir}/${new_name}.${file_ext}" if [ "$full_path" != "$new_full_path" ]; then # 首次试运行时,先将下方mv行替换为echo输出,预览所有重命名结果 mv -i "$full_path" "$new_full_path" echo "已完成重命名: $full_path -> $new_full_path" fi done
上线验证注意事项
- 首次运行脚本时,建议先临时注释
mv命令行,仅通过echo输出预览全目录的重命名结果,确认替换逻辑无偏差后再开启实际重命名操作,避免误改文件 - 正则已做边界防护,不会误匹配长数字串、扩展名内的数字、已经带E前缀的集数标识
内容的提问来源于stack exchange,提问作者Sc0rax
相关产品推荐
相关产品推荐

