如何将指定目录的嵌套子文件夹合并为以原路径拼接命名的单级子文件夹
如何将指定目录的嵌套子文件夹合并为以原路径拼接命名的单级子文件夹
嘿,这个需求我之前帮朋友处理过,刚好可以给你几个靠谱的解决方案,不管你用Linux/macOS终端还是Windows PowerShell,都能轻松搞定👇
方法一:Bash脚本(Linux/macOS通用)
这是最通用的方案,用基础的shell命令就能实现,思路很清晰:先找到所有要处理的文件,把它们的嵌套路径转换成点连接的文件夹名,移动文件后清理空文件夹。
#!/bin/bash # 指定要处理的目标目录 TARGET_DIR="./reports" # 遍历目标目录下所有CSV文件(可修改后缀或去掉过滤处理所有文件) find "$TARGET_DIR" -type f -name "*.csv" | while read -r file; do # 提取文件相对于目标目录的路径(比如:r1/a/b/c/one.csv) relative_path="${file#$TARGET_DIR/}" # 把路径中的斜杠替换成点,得到新的路径格式(比如:r1.a.b.c/one.csv) new_path=$(echo "$relative_path" | sed 's/\//./g') # 拆分出新文件夹名和文件名 new_dir="${new_path%/*}" new_file="${new_path##*/}" # 创建新文件夹(-p确保父目录不存在时也能创建) mkdir -p "$TARGET_DIR/$new_dir" # 移动文件到新位置 mv "$file" "$TARGET_DIR/$new_dir/$new_file" done # 从最深层开始删除所有空的旧嵌套文件夹 find "$TARGET_DIR" -type d -empty -delete
关键步骤解释:
${file#$TARGET_DIR/}:去掉文件路径开头的./reports/,只保留相对路径sed 's/\//./g':把所有斜杠替换成点,实现路径拼接find "$TARGET_DIR" -type d -empty -delete:自动删除空文件夹,避免残留无用目录
方法二:Zsh脚本(更简洁,适合用Zsh的用户)
如果你用的是Zsh(比如macOS默认终端现在是Zsh),可以用Zsh强大的参数扩展功能,代码更短:
#!/usr/bin/zsh TARGET_DIR="./reports" # 递归匹配所有CSV文件 for file in $TARGET_DIR/**/*.csv; do # 提取相对路径 relative=${file#$TARGET_DIR/} # 把路径的目录部分的斜杠换成点,得到新文件夹名 new_dir=${relative:h:s/\//./g} # 创建文件夹并移动文件 mkdir -p $TARGET_DIR/$new_dir mv $file $TARGET_DIR/$new_dir/${relative:t} done # 删除所有空的旧文件夹 rm -rf $TARGET_DIR/**/*(/^F)
亮点说明:
**:Zsh的递归通配符,直接匹配所有子目录下的文件${relative:h}:取相对路径的目录部分,${relative:t}:取文件名,不用手动拆分
方法三:PowerShell脚本(Windows用户适用)
如果是Windows环境,用PowerShell也能实现同样的效果:
$targetDir = "./reports" # 递归找到所有CSV文件 Get-ChildItem -Path $targetDir -Recurse -File -Filter "*.csv" | ForEach-Object { # 提取相对路径 $relativePath = $_.FullName.Substring((Get-Item $targetDir).FullName.Length + 1) # 替换斜杠为点 $newPath = $relativePath -replace "/", "." # 拆分出新文件夹名 $newDir = Join-Path -Path $targetDir -ChildPath ($newPath -replace "\.[^.]+$", "") # 创建文件夹(如果不存在) if (-not (Test-Path $newDir)) { New-Item -ItemType Directory -Path $newDir | Out-Null } # 移动文件 Move-Item -Path $_.FullName -Destination (Join-Path $newDir $_.Name) } # 删除所有空文件夹 Get-ChildItem -Path $targetDir -Recurse -Directory | Where-Object { $_.GetFiles().Count -eq 0 -and $_.GetDirectories().Count -eq 0 } | Remove-Item
重要提醒
- 先备份!:在运行脚本前,最好先复制一份原目录的文件做备份,避免误操作导致文件丢失
- 处理重名文件:如果不同嵌套路径下有同名文件,
mv会直接覆盖,你可以在脚本里加判断逻辑,比如给文件名加后缀(_1、_2)或者跳过 - 灵活调整过滤规则:把
*.csv换成*可以处理所有类型的文件,根据你的实际需求修改
备注:内容来源于stack exchange,提问作者Ashley Coolman




