递归查找含多点点文件名并移除多余点:find与rename联用失效求助
我明白你遇到的问题了——单独用find能精准定位到那些带多余点的文件,单独用rename也能搞定文件名修改,但把俩工具凑一起就掉链子对吧?这多半是文件名里的特殊字符(比如空格、括号)或者rename版本差异搞的鬼,下面给你几个实测有效的解决方案:
解决方案1:用Perl版
rename配合find -exec(推荐,高效) 大部分Debian/Ubuntu系的系统默认是Perl版rename,它支持正则表达式,能批量处理文件名里的多余点。直接用find的-exec参数把文件批量传给rename:
# 替换成你的目标目录路径 find /your/target/directory -type f -exec rename 's/\.+(?=[^.]+$)//g' {} +
正则解释:
's/\.+(?=[^.]+$)//g' 这个正则会匹配最后一个点之前的所有连续点,并把它们替换为空:
\.+:匹配一个或多个点(?=[^.]+$):正向预查,确保这些点后面跟着“非点字符+文件结尾”(也就是最后一个点和后缀名的部分)
测试技巧:
先加-n参数干跑测试,不会实际修改文件,看看输出的重命名逻辑对不对:
find /your/target/directory -type f -exec rename -n 's/\.+(?=[^.]+$)//g' {} +
解决方案2:兼容所有系统的Bash循环方案(适合原生
rename的系统) 如果你的系统是CentOS/RHEL这类用原生rename的(它只支持简单字符串替换,不支持正则),那用Bash循环配合sed来处理更稳妥,还能完美应对带空格的文件名:
find /your/target/directory -type f -print0 | while IFS= read -r -d '' file; do # 拆分目录和文件名 file_dir=$(dirname "$file") old_name=$(basename "$file") # 用sed处理文件名:移除最后一个点之前的所有点 new_name=$(echo "$old_name" | sed -E 's/\.+(?=[^.]+$)//g') # 只有当文件名确实变化时才执行重命名 if [ "$old_name" != "$new_name" ]; then mv "$file_dir/$old_name" "$file_dir/$new_name" echo "重命名:$old_name → $new_name" fi done
关键细节:
-print0和read -d '':确保带空格、换行符的文件名不会被拆分,避免出错IFS=:防止文件名开头的空格被吃掉
为啥之前
find和rename协同失败? 常见的坑有两个:
- 用
xargs传递参数时没处理特殊字符:如果文件名带空格,xargs会把它拆成多个独立参数,rename就会把这些碎片当成不同文件处理,自然出错 - 搞混了
rename版本:Perl版支持正则,原生版只支持rename 旧字符串 新字符串的简单替换,语法完全不兼容,用错版本肯定跑不起来
内容的提问来源于stack exchange,提问作者Henry
相关产品推荐
相关产品推荐

