Tạo phân phối kích thước tệp từ dấu nhắc lệnh


16

Tôi đã có một hệ thống tệp có vài triệu tệp và tôi muốn xem phân phối kích thước tệp theo cách đệ quy trong một thư mục cụ thể. Tôi cảm thấy như điều này là hoàn toàn có thể làm được với một số bash / awk fu, nhưng có thể sử dụng một bàn tay. Về cơ bản tôi muốn một cái gì đó như sau:

1KB: 4123
2KB: 1920
4KB: 112
...
4MB: 238
8MB: 328
16MB: 29138
Count: 320403345

Tôi cảm thấy như thế này không nên quá tệ khi đưa ra một vòng lặp và một số tệp log2 có điều kiện kích thước foo, nhưng tôi dường như không thể đến đó.

Câu hỏi liên quan: Làm cách nào tôi có thể tìm thấy các tệp lớn hơn / nhỏ hơn x byte? .

Câu trả lời:


21

Điều này dường như hoạt động khá tốt:

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

Đầu ra của nó trông như thế này:

         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
trong đó số ở bên trái là giới hạn dưới của một phạm vi từ giá trị đó đến hai lần giá trị đó và số ở bên phải là số tệp trong phạm vi đó.


Tôi đã chỉnh sửa câu trả lời của bạn để sử dụng find thay vì ls để nó được đệ quy và không thực hiện bất kỳ thư mục nào. Bất cứ ai cũng muốn có một vết nứt để làm đẹp đầu ra cột bên trái?
báo

Nhưng câu hỏi ban đầu là về "phân phối kích thước tệp trong một thư mục cụ thể", vì vậy không ổn khi thay đổi lsthành a find. Tôi đang đặt nó trở lại như cũ.
garyjohn

@notpeter: Xin lỗi, tôi không nhận ra bạn là tác giả của câu hỏi. Tôi đã thay đổi câu trả lời của mình để làm cho nó tìm kiếm đệ quy. Trên hệ thống của tôi, tuy nhiên, sử dụng xargsđáng kể nhanh hơn -exec, vì vậy tôi sử dụng phương pháp đó.
garyjohn

1
Đừng lo lắng. Bây giờ chúng tôi chỉ có thể xóa bình luận của chúng tôi là giả vờ nó luôn luôn là câu trả lời đúng. ;)
báo

14

Dựa trên câu trả lời của garyjohn, đây là một lớp lót, cũng định dạng đầu ra cho con người có thể đọc được:

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) }'

Đây là phiên bản mở rộng của nó:

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) }' 

Trong lần đầu tiên, awktôi đã xác định kích thước tệp tối thiểu để thu thập tất cả các tệp nhỏ hơn 1kb đến một nơi. Trong phần hai awk, hàm human(x)được định nghĩa để tạo kích thước có thể đọc được. Phần này dựa trên một trong những câu trả lời ở đây: /unix/44040/a-stiteria-tool-to-convert-a-byte-count-into-human-kib-mib-etc -like-du-ls1

Đầu ra mẫu trông như sau:

  1k:    335
  2k:     16
 32k:      5
128k:     22
  1M:     54
  2M:     11
  4M:     13
  8M:      3

2

Thử đi:

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 

ĐẦU RA:

 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

GIẢI TRÌNH :

  • find . -type f -exec ls -lh {} \;: đủ đơn giản, tìm tệp trong thư mục hiện tại và chạy ls -lhtrên chúng

  • match($5,/([0-9.]+)([A-Z]+)/,k);: điều này sẽ trích xuất kích thước tệp và lưu từng trận đấu vào mảng k.

  • if(!k[2]){print "1K"}: nếu k[2]không xác định kích thước tệp là <1K. Vì tôi tưởng tượng bạn không quan tâm đến kích thước nhỏ như vậy, tập lệnh sẽ in 1Kcho tất cả các tệp có kích thước <= 1K.

  • else{printf "%.0f%s\n",k[1],k[2]} : nếu tệp lớn hơn 1K, hãy làm tròn kích thước tệp thành số nguyên gần nhất và in cùng với công cụ sửa đổi của nó (K, M hoặc G).

  • sort | uniq -c : đếm số lần xuất hiện của mỗi dòng (kích thước tệp) được in.

  • sort -hk 2: sắp xếp theo trường thứ hai ở định dạng có thể đọc được. Cách này, 7Gđược sắp xếp sau 8M.


Tôi đánh giá cao những lời giải thích, tôi nghĩ nó hữu ích cho những người đang cố gắng tìm ra nó. Điều đó nói rằng, tập lệnh của bạn không hoạt động với tôi vì hai lý do 1) GNU LS của tôi đã cũ và do đó cung cấp đầu ra kích thước có thể đọc được khác nhau cho 'ls -lh' (byte không phải K / M / G / T) và 2) vì Có quá nhiều thùng. Với kích thước tệp trong khoảng từ 1K đến 1G, có 2000 nhóm, một nửa trong số đó là 1KB trong đó có 1 MB. Đáng giá cho 'uniq -c' đó là mới đối với tôi.
báo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.