我有一个包含几百万个文件的文件系统,我想递归查看特定目录中文件大小的分布。我觉得这完全可以通过一些 bash/awk fu 来实现,但可能需要一些技巧。基本上我想要类似以下内容:
1KB: 4123
2KB: 1920
4KB: 112
...
4MB: 238
8MB: 328
16MB: 29138
Count: 320403345
我觉得给定一个循环和一些条件 log2 文件大小 foo,这应该不会太糟糕,但我似乎无法到达那里。
相关问题:我如何才能找到大于/小于 x 字节的文件?。
答案1
这似乎很有效:
find . -type f -print0 | xargs -0 ls -l | awk '{size[int(log($5)/log(2))]++}END{for (i in size) printf("%10d %3d\n", 2^i, size[i])}' | sort -n
其输出如下所示:
0 1
8 3
16 2
32 2
64 6
128 9
256 9
512 6
1024 8
2048 7
4096 38
8192 16
16384 12
32768 7
65536 3
131072 3
262144 3
524288 6
2097152 2
4194304 1
33554432 1
134217728 4
其中左边的数字是从该值到该值的两倍范围的下限,右边的数字是该范围内的文件数。
答案2
根据 garyjohn 的回答,这里有一行代码,它还将输出格式化为人类可读的:
find . -type f -print0 | xargs -0 ls -l | awk '{ n=int(log($5)/log(2)); if (n<10) { n=10; } size[n]++ } END { for (i in size) printf("%d %d\n", 2^i, size[i]) }' | sort -n | awk 'function human(x) { x[1]/=1024; if (x[1]>=1024) { x[2]++; human(x) } } { a[1]=$1; a[2]=0; human(a); printf("%3d%s: %6d\n", a[1],substr("kMGTEPYZ",a[2]+1,1),$2) }'
以下是其扩展版本:
find . -type f -print0 \
| xargs -0 ls -l \
| awk '{ n=int(log($5)/log(2)); \
if (n<10) n=10; \
size[n]++ } \
END { for (i in size) printf("%d %d\n", 2^i, size[i]) }' \
| sort -n \
| awk 'function human(x) { x[1]/=1024; \
if (x[1]>=1024) { x[2]++; \
human(x) } } \
{ a[1]=$1; \
a[2]=0; \
human(a); \
printf("%3d%s: %6d\n", a[1],substr("kMGTEPYZ",a[2]+1,1),$2) }'
在第一个中,awk
我定义了一个最小文件大小,将所有小于 1kb 的文件收集到一个地方。在第二个中awk
,定义了一个函数human(x)
来创建一个人类可读的大小。这部分基于以下答案之一:https://unix.stackexchange.com/questions/44040/a-standard-tool-to-convert-a-byte-count-into-human-kib-mib-etc-like-du-ls1
示例输出如下所示:
1k: 335
2k: 16
32k: 5
128k: 22
1M: 54
2M: 11
4M: 13
8M: 3
答案3
尝试这个:
find . -type f -exec ls -lh {} \; |
gawk '{match($5,/([0-9.]+)([A-Z]+)/,k); if(!k[2]){print "1K"} \
else{printf "%.0f%s\n",k[1],k[2]}}' |
sort | uniq -c | sort -hk 2
输出 :
38 1K
14 2K
1 30K
2 62K
12 2M
2 3M
1 31M
1 46M
1 56M
1 75M
1 143M
1 191M
1 246M
1 7G
解释 :
find . -type f -exec ls -lh {} \;
:很简单,在当前目录中找到文件并运行ls -lh
它们match($5,/([0-9.]+)([A-Z]+)/,k);
:这将提取文件大小,并将每个匹配项保存到数组中k
。if(!k[2]){print "1K"}
:如果k[2]
未定义,则文件大小小于 1K。由于我猜想您并不关心如此小的文件大小,因此脚本将打印1K
所有大小小于等于 1K 的文件。else{printf "%.0f%s\n",k[1],k[2]}
:如果文件大于 1K,则将文件大小四舍五入为最接近的整数,并与其修饰符(K、M 或 G)一起打印。sort | uniq -c
:计算每行打印的次数(文件大小)。sort -hk 2
:按照第二个字段以人性化的方式排序。这样,7G
就排在 之后8M
。
答案4
我偶然发现了这个问题,因为我也想查看我的文件大小的分布。然而,就我而言,我不需要 2 的幂次存储桶。我使用了不同的 bash 命令来查看文件大小分布:
ls -URs1Q --block-size=M | cut -d\" -f1 | tr -d ' ' | sort -n | uniq -c
解释选项:
U
:不对文件进行排序,这样可以更快R
:递归,如果你想包含嵌套目录s
:打印每个文件的大小1
:在一行上打印每个条目,以避免列Q
:引用文件名,以便我们可以使用它作为分隔符--block-size=M
:按 MB 缩放尺寸cut -d\" -f1
:在第一个引号处剪切并返回第一个元素 = sizetr -d ' '
:删除所有空格字符sort -n
:按自然顺序对值进行排序uniq -c
:仅显示唯一值,但包含计数
这将显示如下结果:
28 0M
228602 1M
1393 2M
238 3M
107 4M
82 5M
41 6M
32 7M
33 8M
24 9M
24 10M
15 11M
20 12M
15 13M
14 14M
19 15M
8 16M
13 17M
6 18M
7 19M
4 20M
6 21M
2 22M
1 23M
4 24M
4 25M
4 27M
1 29M
2 30M
1 2239M
对于目录,总数包含在列表中,您可以使用以下命令省略它们:
ls -URs1Q --block-size=M | cut -d\" -f1 | tr -d ' ' | sort -n | uniq -c | grep -v total
它没有正确回答 OP 的问题,但它可能有助于其他寻找类似但不同解决方案的人。