从命令提示符生成文件大小分布

从命令提示符生成文件大小分布

我有一个包含几百万个文件的文件系统,我想递归查看特定目录中文件大小的分布。我觉得这完全可以通过一些 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:在第一个引号处剪切并返回第一个元素 = size

  • tr -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 的问题,但它可能有助于其他寻找类似但不同解决方案的人。

相关内容