我有一个大的n级目录,结构如下:
root
|
subdir1
|
sub_subdir1
|
....(n-2 levels).....
|
file1
|
subdir2
|
sub_subdir2
|
....(n-2 levels).....
|
file2
我想展平目录,以便所有级别 1子目录包含文件。我还想将级别 2 删除为 (n-1)子子目录因为它们不包含文件。请注意,子目录都有不同的名称。
期望的结果
root
|
subdir1
|
file1
|
subdir2
|
file2
我发现很多帖子解释了方法压扁目录,但没有解释如何以受控方式执行此操作,即
- 通过指定要展平的级别
- 或者对根目录中的所有子目录递归执行此操作
答案1
使用 zsh:
cd /root
for subdir in subdir*
do
mv "$subdir"/**/*(.) "$subdir"
rm -r "$subdir"/*(/)
done
这:
- 更改“/root”目录(来自您的示例)
- 循环遍历每个名为的子目录
subdir*
(同样来自您的示例:匹配 subdir1 和 subdir1) - 将该子目录下的(预期的,但会匹配所有)匹配文件移动到该子目录中。这使用了 zsh 的
**
递归 globbing 功能,然后受到 glob 限定符的限制,*(.)
该限定符表示:此目录中的任何条目都是普通文件 - 移动文件后,递归删除该子目录下的每个子目录;这再次使用 zsh glob 限定符
*(/)
,它表示匹配目录条目。
答案2
在 bash 中,执行以下操作:
shopt -s dotglob
for d in root/*/
do
find "$d" -type f -exec mv -i -t "$d" {} +
find "$d" -mindepth 1 -type d -delete
done
这会查看“ root
”中的所有内容,包括点文件。如果您不需要查看点文件,请忽略shopt -s dotglob
.警告:请勿添加.*
或 命令。root/.*
for
/
正如Jeff所建议的, glob()末尾的只为我们提供了子目录,因此我们不需要测试每一个子目录(例如,使用 )。root/*/
if
对于每一个子目录of root
,找到该子目录及其下的所有文件并将它们移动到该子目录中。用于 -i
防止覆盖文件(例如,如果您有多个名为file1
Distributed under 的文件subdir1
)。
-i
意思是“交互式”,它会询问你是否应该覆盖现有文件。请注意,它可能拒绝这样做,即使你说“是”。如果您的版本 mv
不支持该-t
选项,请将命令替换mv
为
find "$d" -type f -exec mv -i {} "$d" ';'
然后删除顶级子目录下的所有子目录。请注意,如果没有移动任何文件,此 ( find
... ) 将失败。-delete