如何编写Linux Shell脚本递归替换文件名中数字间的点为连字符
解决递归替换文件名中数字间点为连字符的问题
原脚本的问题
你之前的脚本存在两个核心问题:
for file in *.*仅能匹配当前目录下包含点的文件,无法递归处理子目录,还会漏掉不含点的文件名${file//\d\.\d,\d\-\d}是错误的替换语法:bash的参数扩展仅支持通配符匹配,不支持\d这类正则元字符,且替换格式完全不符合规则
正确的bash脚本
下面的脚本会递归遍历指定目录(或当前目录),仅将数字与数字之间的点替换为连字符,保留文件名中其他位置的点(比如Mr.里的点、后缀名的点):
#!/bin/bash # 优先使用传入的目录参数,无参数则用当前目录 TARGET_DIR="${1:-.}" # 递归查找所有文件,避免处理目录 find "$TARGET_DIR" -type f | while IFS= read -r full_path; do # 拆分文件目录和文件名 file_dir=$(dirname "$full_path") old_name=$(basename "$full_path") # 用sed替换所有数字间的点:捕获前后数字,将中间的点换成连字符 new_name=$(echo "$old_name" | sed -E 's/([0-9])\.([0-9])/\1-\2/g') # 仅当文件名有变化时执行重命名,避免无效操作 if [ "$old_name" != "$new_name" ]; then # 加上-v参数可以显示重命名过程,方便验证 mv -v "$full_path" "$file_dir/$new_name" fi done read -n 1 -p "Hit any key to exit"
脚本说明
- 递归处理:用
find命令遍历目标目录下所有文件,包括子目录中的文件 - 文件名安全处理:
IFS= read -r full_path确保能正确处理包含空格、特殊字符的文件名 - 精准替换:
sed -E 's/([0-9])\.([0-9])/\1-\2/g'使用扩展正则表达式,仅匹配数字.数字的组合,将中间的点替换为连字符,全局替换保证处理多个连续的数字点(比如1.1.4→1-1-4) - 安全校验:只有当新旧文件名不同时才执行重命名,避免不必要的操作
使用方法
- 将脚本保存为
fix_filenames.sh - 赋予执行权限:
chmod +x fix_filenames.sh - 运行脚本:
- 处理当前目录:
./fix_filenames.sh - 处理指定目录:
./fix_filenames.sh /path/to/your/media/folder
- 处理当前目录:
测试建议
在实际执行重命名前,可以先将mv -v改成echo mv -v,这样脚本只会输出将要执行的重命名操作,不会实际修改文件名,确认无误后再改回mv -v执行。
特殊需求调整
如果需要仅替换文件名开头的连续数字段中的点(比如你的示例中3.4不想替换),可以将sed命令修改为:
new_name=$(echo "$old_name" | sed -E 's/^([0-9]+)\.([0-9]+)/\1-\2/g; s/(-[0-9]+)\.([0-9]+)/\1-\2/g')
这个正则会仅处理开头的数字-点序列,比如1.2 3.4 foo.bar会变成1-2 3.4 foo.bar,符合你给出的示例期望。
内容的提问来源于stack exchange,提问作者Chris Fox
相关产品推荐
相关产品推荐

