按深度排序文件(bash)

时间:2012-07-28 19:25:28

标签: bash sorting

bash中是否有一种方法可以从深度顺序对目录中的文件进行排序,例如首先打印当前目录中的文件,然后打印子目录或子目录中的文件,依此类推,他们的深度。

5 个答案:

答案 0 :(得分: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)。

答案 1 :(得分:4)

将find的“-printf”功能与sort结合使用。亲眼看看:

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//;'

提示:研究查找联机帮助页以获得更多类似于printf%d的技巧。

答案 2 :(得分:2)

一种似是而非的技术会使用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的方式,但是有效。

答案 3 :(得分:1)

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

<强> test.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

答案 4 :(得分:0)

使用find命令:

find . -depth

来自man find

  

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