5

bash 中是否有办法按深度顺序对目录中的文件进行排序,例如首先打印当前目录中的文件,然后打印子目录或子目录中的文件等等,总是从它们的深度来看。

4

5 回答 5

9

将 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 的技巧。

于 2016-10-14T09:23:55.320 回答
4

最简单的解决方案:

$ 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)。

于 2012-07-30T05:17:46.860 回答
3

一种合理的技术将用于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 编写方式,但它确实有效。

于 2012-07-28T20:40:58.677 回答
1

使用函数递归遍历文件系统

测试.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
于 2012-07-28T21:04:43.133 回答
0

使用find命令:

find . -depth

来自man find

-depth 在目录本身之前处理每个目录的内容。

于 2012-07-28T19:27:17.973 回答