bash 中是否有办法按深度顺序对目录中的文件进行排序,例如首先打印当前目录中的文件,然后打印子目录或子目录中的文件等等,总是从它们的深度来看。
5 回答
将 find 的“-printf”功能与排序结合使用。你自己看:
find . -printf "%d %p\n"|sort -n
它生成一个深度排序列表(在第一列显示深度,在第二列显示文件路径)。这打印在我当前的目录中:
0 .
1 ./bin
1 ./log
1 ./templates
2 ./bin/cc_env
3 ./files/test/mail.txt
如果要剥离第一列,我们可以使用 perl:
find . -printf "%d %p\n"|sort -n|perl -pe 's/^\d+\s//;'
然后你就走了。perl 过滤器将删除所有前导数字。如果您想省略目录本身,请使用“-type f”参数:
find . -type f -printf "%d %p\n"|sort -n|perl -pe 's/^\d+\s//;'
提示:研究 find 手册页以获得更多类似 printf %d 的技巧。
最简单的解决方案:
$ echo * */* */*/* */*/*/* */*/*/*/* */*/*/*/*/*
a a/b a/b/c a/b/c/d1 a/b/c/d2 a/b/c/d1/e a/b/c/d2/e a/b/c/d1/e/f a/b/c/d2/e/f
或者,在列中:
$ echo * */* */*/* */*/*/* */*/*/*/* */*/*/*/*/* |tr ' ' '\n'
a
a/b
a/b/c
a/b/c/d1
a/b/c/d2
a/b/c/d1/e
a/b/c/d2/e
a/b/c/d1/e/f
a/b/c/d2/e/f
树的深度在示例中是硬编码的,但您可以编写一个小脚本并使其更灵活:
A="*"
while true
do
B=$(echo $A)
[ "$B" = "$A" ] && break
echo $B
A="$A/*"
done | tr ' ' '\n'
使用示例:
$ A="*"; while true; do B=$(echo $A); [ "$B" = "$A" ] && break; echo $B; A="$A/*"; done | tr ' ' '\n'
a
a/b
a/b/c
a/b/c/d1
a/b/c/d2
a/b/c/d1/e
a/b/c/d2/e
a/b/c/d1/e/f
a/b/c/d2/e/f
为树提供了示例:
$ mkdir -p a/b/c/d{1,2}/e/f
$ tree .
.
└── a
└── b
└── c
├── d1
│ └── e
│ └── f
└── d2
└── e
└── f
9 directories, 0 files
查找/深度解决方案显然不起作用,因为find
会一个接一个地显示子树。-depth
键表示必须在哪个方向显示子树。但这并不意味着,当然,输出将按深度排序。
$ find .
.
./a
./a/b
./a/b/c
./a/b/c/d2
./a/b/c/d2/e
./a/b/c/d2/e/f
./a/b/c/d1
./a/b/c/d1/e
./a/b/c/d1/e/f
$ find . -depth
./a/b/c/d2/e/f
./a/b/c/d2/e
./a/b/c/d2
./a/b/c/d1/e/f
./a/b/c/d1/e
./a/b/c/d1
./a/b/c
./a/b
./a
.
如您所见,两种情况下的答案都是不正确的(有和没有-find
)。
一种合理的技术将用于find
生成文件路径名,然后处理文件名,以便路径中斜杠数量的计数在名称之前,然后您可以按斜杠计数(深度)然后按名称排序. 简单的解决方案假定您的文件名中没有换行符(其他空格和奇数字符无关紧要)。有趣/棘手的部分是找到一种干净的方法来计算给定行中斜线的数量。
find . -type f -print |
perl -n -e '$x = $_; $x =~ tr%/%%cd; print length($x), " $_";' |
sort -k 1n -k 2 |
sed 's/^[0-9][0-9]* //'
可能有一种更紧凑的 Perl 编写方式,但它确实有效。
使用函数递归遍历文件系统
测试.sh:
#!/bin/bash
function traverse() {
find $1 -mindepth 1 -maxdepth 1 ! -type d -exec echo "$2"{} \;
for d in $(find $1 -mindepth 1 -maxdepth 1 -type d ! -name ".")
do
# if you just need files comment out next line
echo "$2$d"
traverse "$d" "${2} "
done
}
traverse $1
用法:
./test.sh dir
给出输出:
./test.sh
./testA
./testA/dat2
./testA/dat1
./testA/testB
./testA/testB/dat4
./testC
./testC/dat3
使用find
命令:
find . -depth
来自man find
:
-depth 在目录本身之前处理每个目录的内容。