สร้างการกระจายขนาดไฟล์จากพรอมต์คำสั่ง


16

ฉันมีระบบไฟล์ที่มีไฟล์สองล้านไฟล์และฉันต้องการดูการกระจายขนาดไฟล์แบบเรียกซ้ำในไดเรกทอรีเฉพาะ ฉันรู้สึกว่านี่ใช้ได้กับ bash / awk fu แต่สามารถใช้มือได้ โดยทั่วไปฉันต้องการบางสิ่งบางอย่างดังต่อไปนี้:

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

ฉันรู้สึกว่าสิ่งนี้ไม่ควรเลวร้ายเกินไปถ้ามีลูปและไฟล์บันทึกขนาด log2 ที่มีเงื่อนไขบางอย่าง แต่ฉันไม่สามารถไปถึงที่นั่นได้

คำถามที่เกี่ยวข้อง: ฉันจะค้นหาไฟล์ที่ใหญ่กว่า / เล็กกว่า x ไบต์ได้อย่างไร .

คำตอบ:


22

ดูเหมือนว่าจะทำงานได้ดี:

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
โดยที่ตัวเลขทางด้านซ้ายคือขีด จำกัด ล่างของช่วงจากค่านั้นถึงสองเท่าของค่านั้นและหมายเลขด้านขวาคือจำนวนไฟล์ในช่วงนั้น


ฉันแก้ไขคำตอบของคุณเพื่อใช้ค้นหาแทนที่จะเป็น ls เพื่อให้ซ้ำและไม่นับไดเรกทอรีใด ๆ ทุกคนต้องการที่จะถอดที่คอลัมน์ด้านซ้ายมือสวยขึ้น?
notpeter

แต่คำถามเดิมเกี่ยวกับ "การกระจายตัวของขนาดของไฟล์ในไดเรกทอรีโดยเฉพาะอย่างยิ่ง" ดังนั้นจึงไม่ได้ตกลงที่จะเปลี่ยนไปls findฉันเอามันกลับมาเหมือนเดิม
garyjohn

@notpeter: ขออภัยฉันไม่รู้จักคุณในฐานะผู้เขียนคำถาม ฉันเปลี่ยนคำตอบเพื่อให้ค้นหาซ้ำได้ ในระบบของฉันแม้ว่าใช้xargsเป็นอย่างมีนัยสำคัญได้เร็วกว่า-execดังนั้นผมจึงใช้วิธีการที่
garyjohn

1
ไม่ต้องห่วง. ตอนนี้เราสามารถลบความคิดเห็นของเราถูกแกล้งทำเป็นว่ามันเป็นคำตอบที่ถูกเสมอ ;)
บันทึก

14

ตามคำตอบของ 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)ถูกกำหนดเพื่อสร้างขนาดที่มนุษย์สามารถอ่านได้ ส่วนนี้ขึ้นอยู่กับหนึ่งในคำตอบที่นี่: /unix/44040/a-standard-tool-to-convert-a-byte-count-into-human-kib-mib-etc เหมือน-du-LS1

ผลลัพธ์ตัวอย่าง:

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

2

ลองสิ่งนี้:

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 {} \;: ง่ายพอค้นหาไฟล์ใน dir ปัจจุบันแล้วรัน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: จัดเรียงตามฟิลด์ที่สองในรูปแบบที่มนุษย์อ่านได้ วิธีนี้จะถูกจัดเรียงหลัง7G8M


ฉันซาบซึ้งกับคำอธิบายฉันคิดว่ามันมีประโยชน์สำหรับคนที่พยายามคิดออก ที่กล่าวว่าสคริปต์ของคุณไม่ทำงานสำหรับฉันด้วยเหตุผลสองประการ 1) GNU LS ของฉันเก่าและให้ขนาดเอาต์พุตที่มนุษย์สามารถอ่านได้ที่แตกต่างกันสำหรับ 'ls -lh' (ไบต์ไม่ใช่ K / M / G / T) และ 2) เพราะ มีถังมากเกินไป ด้วยขนาดไฟล์ระหว่าง 1K ถึง 1G จะมี 2,000 ฝากข้อมูลครึ่งหนึ่งเป็นครึ่ง 1KB ซึ่งมี 1MB มันคุ้มค่าสำหรับ 'uniq -c' ที่ใหม่สำหรับฉัน
notpeter
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.