假设我有一个source/
目录,它有许多子目录。有些子目录下又有子子目录,有些子子目录下又有子子子目录,等等。
我要做的是递归地查找所有最低级子目录(没有任何进一步子目录的子目录)source/
并将它们移动到新的目标目录。
例如,假设原文source/
如下:
/source/dir1 --Subdirectory without sub-subdirectory
/source/dir2 --Subdirectory with sub-subdirectory
/source/dir2/dir2.a --Sub-subdirectory without sub-sub-subdirectory
/source/dir2/dir2.b --Sub-subdirectory without sub-sub-subdirectory
那么操作之后target
目录应该是这样的:
/target/dir1
/target/dir2.a
/target/dir2.b
有没有办法用终端命令来做到这一点?
答案1
假设您所在的文件系统的叶目录恰好有 2 个硬链接,则您可以像这样组合使用 find、xargs 和 mv:
$ find . -type d -printf "%n %p\n" \
| grep '^2 ' \
| perl -ne 'chomp; s/[0-9]+\s+//; print "$_\0";' \
| xargs -0 -I'{}' mv -v '{}' /target/
这使用 find 来仅查找目录并打印这些目录具有的硬链接数量。
然后我们使用 grep 删除任何不是“叶子”的内容。
接下来我们使用 Perl 来切断硬链接数,并打印以 分隔的文件\0
。
最后,让我们使用带有-0
标志的 xargs 将找到的目录移动到目标目录中。
对于包含空格的文件,使用空值 ( \0
) 而不是换行符或空格非常重要。如果您的目录名称保证不包含空格,那么您可以稍微简化一下。
$ find . -type d -printf "%n %p\n" | grep '2 ' | cut -d " " -f 2 | xargs -I'{}' mv -v '{}' /target/
但谨慎一点总比后悔好。
答案2
一种方法可能是使用find
来获取每个目录,并将结果传递给第二个目录,并且仅当第二个目录返回给定目录下的任何目录find
时才执行移动,例如find
while read -rd $'\0' dir; do
[[ -z $(find "$dir" -mindepth 1 -type d) ]] && mv -t path/to/target "$dir"
done < <(find -depth -type d -print0)
或者
find -depth -type d -execdir \
bash -c '[[ -z $(find "$0" -mindepth 1 -type d) ]] && mv -t path/to/target "$0"' {} +
例如
$ tree .
.
├── dir1
└── dir2
├── dir2.a
└── dir2.b
然后
$ while read -rd $'\0' dir; do [[ -z $(find "$dir" -mindepth 1 -type d) ]] && echo mv -t path/to/target "$dir"; done < <(find -depth -type d -print0)
mv -t path/to/target ./dir1
mv -t path/to/target ./dir2/dir2.b
mv -t path/to/target ./dir2/dir2.a