Unix - 只列出包含子目录的目录
Unix - Only list directories which contain a subdirectory
如何在 Unix 中打印 shell 树中包含其他目录的目录数?
我还没有找到像 find
或 ls
这样的命令的解决方案。
您可以使用find
命令:find . -type d -not -empty
这将打印每个不为空的子目录。您可以使用 -maxdepth
.
控制搜索的深度
要打印号码,您可以使用wc -l
。
find . -type d -not -empty | wc -l
如果您生成一个特定目录下所有目录的列表,然后从名称中删除最后一个部分,您将得到一个包含子目录的目录列表,但该列表中可能有重复项。因此,您需要 post-process 列表,产生(作为第一个近似值):
find ${base:-.} -type d |
sed 's%/[^/]*$%%' |
sort -u
查找变量$base
中列出的目录下的所有目录,默认为当前目录,并打印它们的名称。该代码假定您没有名称中带有换行符的目录。如果这样做,可以进行修复,但最好的修复方法是重命名目录。 sed
命令删除最后一个斜杠及其后的所有内容。排序消除了重复条目。剩下的是包含子目录的目录列表。
嗯,或多或少。有一种退化的情况需要考虑:列表中的顶级目录将被列出,无论它们是否有子目录。解决这个问题有点困难。在删除尾随 material 之前,您需要删除与指定给 find
的目录完全匹配的任何输出行。所以,你需要这样的东西:
{
printf '\#^%s$#d\n' ${base:-.}
echo 's%/[^/]*$%%'
} > sed.script
find ${base:-.} -type d |
sed -f sed.script |
sort -u
rm -f sed.script
\#^%s$#d
假定您不在目录名称中使用 #
。如果确实要使用它,则需要找到一个不在名称中使用的字符(可能是 Control-A)并用它代替 #
。如果您绝对可以面对任何字符,那么您将需要做更多的工作来转义一些晦涩的字符,例如 Control-A,当它出现在目录名称中时。
还有一个问题:使用像 sed.script
这样的固定名称作为临时文件名是不好的(出于多种原因——例如两个人试图同时 运行 脚本相同的目录,尽管它也可能存在安全风险),因此使用 mktemp
创建一个临时文件名:
tmp=$(mktemp ${TMPDIR:-/tmp}/dircnt.XXXXXX)
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
{
printf '\#^%s$#d\n' ${base:-.}
echo 's%/[^/]*$%%'
} > $tmp
find ${base:-.} -type d |
sed -f $tmp |
sort -u
rm -f $tmp
trap 0
这处理最常见的信号(HUP、INT、QUIT、PIPE、TERM)并删除临时文件,即使其中之一到达也是如此。
显然,如果您只想计算目录的数量,可以通过 wc -l
将上述命令的输出通过管道传输来获取计数。
ls -1d */*/. | cut -d / -f1 | uniq
如何在 Unix 中打印 shell 树中包含其他目录的目录数?
我还没有找到像 find
或 ls
这样的命令的解决方案。
您可以使用find
命令:find . -type d -not -empty
这将打印每个不为空的子目录。您可以使用 -maxdepth
.
要打印号码,您可以使用wc -l
。
find . -type d -not -empty | wc -l
如果您生成一个特定目录下所有目录的列表,然后从名称中删除最后一个部分,您将得到一个包含子目录的目录列表,但该列表中可能有重复项。因此,您需要 post-process 列表,产生(作为第一个近似值):
find ${base:-.} -type d |
sed 's%/[^/]*$%%' |
sort -u
查找变量$base
中列出的目录下的所有目录,默认为当前目录,并打印它们的名称。该代码假定您没有名称中带有换行符的目录。如果这样做,可以进行修复,但最好的修复方法是重命名目录。 sed
命令删除最后一个斜杠及其后的所有内容。排序消除了重复条目。剩下的是包含子目录的目录列表。
嗯,或多或少。有一种退化的情况需要考虑:列表中的顶级目录将被列出,无论它们是否有子目录。解决这个问题有点困难。在删除尾随 material 之前,您需要删除与指定给 find
的目录完全匹配的任何输出行。所以,你需要这样的东西:
{
printf '\#^%s$#d\n' ${base:-.}
echo 's%/[^/]*$%%'
} > sed.script
find ${base:-.} -type d |
sed -f sed.script |
sort -u
rm -f sed.script
\#^%s$#d
假定您不在目录名称中使用 #
。如果确实要使用它,则需要找到一个不在名称中使用的字符(可能是 Control-A)并用它代替 #
。如果您绝对可以面对任何字符,那么您将需要做更多的工作来转义一些晦涩的字符,例如 Control-A,当它出现在目录名称中时。
还有一个问题:使用像 sed.script
这样的固定名称作为临时文件名是不好的(出于多种原因——例如两个人试图同时 运行 脚本相同的目录,尽管它也可能存在安全风险),因此使用 mktemp
创建一个临时文件名:
tmp=$(mktemp ${TMPDIR:-/tmp}/dircnt.XXXXXX)
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
{
printf '\#^%s$#d\n' ${base:-.}
echo 's%/[^/]*$%%'
} > $tmp
find ${base:-.} -type d |
sed -f $tmp |
sort -u
rm -f $tmp
trap 0
这处理最常见的信号(HUP、INT、QUIT、PIPE、TERM)并删除临时文件,即使其中之一到达也是如此。
显然,如果您只想计算目录的数量,可以通过 wc -l
将上述命令的输出通过管道传输来获取计数。
ls -1d */*/. | cut -d / -f1 | uniq