Bash嵌套子目录文件重命名出错,求排查问题原因
Bash文件重命名:路径处理错误分析与修复
问题背景
你有一批带多级路径的文件:
www.me.com/a/b/c/file.csv www.you.com/a/b/c/d/e/file.csv www.us.com/a/file.csv
想要重命名为「目录路径(去掉斜杠)+原文件名」的形式,保留在原目录下:
www.me.com/a/b/c/www.me.comabcfile.csv www.you.com/a/b/c/d/e/www.you.comabcdefile.csv www.us.com/a/www.us.comafile.csv
但执行 rename 's/(.*)\//$1\/$1/' * 后得到了异常长的文件名,以下是问题原因和解决办法。
你的命令哪里错了?
- 贪婪匹配+重复替换触发无限追加:Perl版
rename默认会对匹配到的内容重复执行替换规则。你的正则(.*)\/里的.*是贪婪匹配,会抓取最后一个斜杠前的所有内容,替换后文件名变成「路径/路径原文件名」,但这个新文件名又会再次匹配规则,导致路径被反复追加,最终文件名变得超长。 - 未处理路径里的斜杠:你需要把路径里的
/全部去掉再拼接到文件名前,但原命令只是把路径原样重复了一次,完全没做去斜杠的处理,根本达不到预期格式。
正确的实现方式
方法1:用Perl版rename直接处理
# 先开启bash的globstar,支持匹配所有子目录 shopt -s globstar rename 's|(.+)/(.+)|$1/`echo $1 | tr -d /`$2|e' **/file.csv
- 用
|作为正则分隔符,避免和路径的/冲突; (.+)/(.+)分别捕获文件所在的完整目录和原文件名;e修饰符允许在替换部分执行shell命令,echo $1 | tr -d /会把目录里的所有/删掉;**/file.csv匹配所有子目录下的file.csv。
方法2:用遍历+mv处理(更通用)
如果你的系统没有Perl版rename,或者需要更直观的逻辑,可以用这个脚本:
shopt -s globstar for file in **/file.csv; do # 提取文件所在目录 dir_path=$(dirname "$file") # 提取原文件名 original_name=$(basename "$file") # 移除目录字符串里的所有斜杠 clean_dir=$(echo "$dir_path" | tr -d '/') # 执行重命名 mv "$file" "$dir_path/$clean_dir$original_name" done
内容的提问来源于stack exchange,提问作者Christopher Penn
相关产品推荐
相关产品推荐

