กำลังค้นหาไฟล์หร็อมแหร็ม?


19

มีวิธีที่ตรงไปตรงมาเพื่อค้นหาไฟล์ที่กระจัดกระจายทั้งหมดในระบบของฉันหรือในไดเรกทอรีต้นไม้โดยเฉพาะ?

ถ้ามันเกี่ยวข้องฉันใช้zshUbuntu 12.04 แม้ว่าคำตอบ Unix-y ทั่วไปสำหรับ bash / sh เช่นจะเป็นเรื่องปกติ

แก้ไข : เพื่อชี้แจงฉันกำลังมองหาไฟล์ที่กระจัดกระจายไม่ได้ตรวจสอบสถานะการกระจัดกระจายของไฟล์เดียว



2
อะไรทำให้คุณรู้สึกว่าการค้นหาไฟล์ที่กระจัดกระจายไม่ได้เกี่ยวข้องกับการตรวจสอบสถานะการกระจายของแต่ละบุคคล
jlliagre

คำตอบ:


11

บนระบบ (และระบบไฟล์) ที่สนับสนุนการSEEK_HOLE lseekตั้งค่าสถานะ (เช่น Ubuntu 12.04 ของคุณใน ext4 จะ) และสมมติว่าค่าสำหรับSEEK_HOLE4 เท่ากับบน Linux:

if perl -le 'seek STDIN,0,4;$p=tell STDIN;
   seek STDIN,0,2; exit 1 if $p == tell STDIN'< the-file; then
  echo the-file is sparse
else
  echo the-file is not sparse
fi

ไวยากรณ์เชลล์นั้นคือ POSIX สิ่งที่ไม่ใช่แบบพกพาในนั้นและว่าperlSEEK_HOLE

lseek(SEEK_HOLE)ค้นหาจุดเริ่มต้นของรูแรกในไฟล์หรือจุดสิ้นสุดของไฟล์หากไม่พบรู ด้านบนเรารู้ว่าไฟล์ไม่กระจัดกระจายเมื่อlseek(SEEK_HOLE)พาเราไปยังจุดสิ้นสุดของไฟล์ (ไปยังสถานที่เดียวกันเป็นlseek(SEEK_END))

หากคุณต้องการแสดงรายการไฟล์กระจัดกระจาย:

find . -type f ! -size 0 -exec perl -le 'for(@ARGV){open(A,"<",$_)or
  next;seek A,0,4;$p=tell A;seek A,0,2;print if$p!=tell A;close A}' {} +

GNU find(ตั้งแต่รุ่น 4.3.3) -printf %Sจะต้องรายงานความกระจัดกระจายของไฟล์ ใช้วิธีการเดียวกันกับคำตอบที่ frostschutzใช้อัตราส่วนของการใช้ดิสก์เทียบกับขนาดไฟล์ดังนั้นจึงไม่รับประกันว่าจะรายงานไฟล์ที่กระจัดกระจายทั้งหมด (เช่นเมื่อมีการบีบอัดที่ระดับระบบไฟล์หรือพื้นที่ที่บันทึกไว้ไม่รู ชดเชยค่าโสหุ้ยโครงสร้างพื้นฐานของระบบแฟ้มหรือแอตทริบิวต์เพิ่มเติมขนาดใหญ่) แต่จะทำงานบนระบบที่ไม่มีSEEK_HOLEหรือระบบไฟล์ที่SEEK_HOLEไม่ได้ใช้งาน ที่นี่ด้วยเครื่องมือ GNU:

find . -type f ! -size 0 -printf '%S:%p\0' |
  awk -v RS='\0' -F : '$1 < 1 {sub(/^[^:]*:/, ""); print}'

(โปรดทราบว่ารุ่นก่อนหน้าของคำตอบนี้ไม่ทำงานอย่างถูกต้องเมื่อfindแสดงความกระจัดกระจายเช่น 3.2e-05 ขอบคุณคำตอบของ @ flashydave ที่นำมาให้ฉัน)


ความคิดเห็นเช่นเดียวกับข้างต้น; ฉันกำลังมองหาวิธีในการค้นหาไฟล์ที่กระจัดกระจายทั้งหมดไม่ได้ตรวจสอบไฟล์เฉพาะ
Andrew Ferrier

1
บางทีfindควรแยก 0-byte-files เอาล่ะ
frostschutz

@ frostschutz จุดดีตอบปรับปรุงแล้ว
Stéphane Chazelas

พบกับfind -printf '%S'! :-)
frostschutz

1
@Brian เปลี่ยนtrคำสั่งด้วยxargs -r0 rm -f
Stéphane Chazelas

8

โดยทั่วไปไฟล์จะกระจัดกระจายเมื่อจำนวนบล็อกที่จัดสรรมีขนาดเล็กกว่าขนาดไฟล์ (ที่นี่ใช้ GNU statตามที่พบใน Ubuntu แต่ระวังระบบอื่น ๆ อาจมีการใช้งานร่วมกันไม่ได้stat)

if [ "$((`stat -c '%b*%B-%s' -- "$file"`))" -lt 0 ]
then
    echo "$file" is sparse
else
    echo "$file" is not sparse
fi

แตกต่างกับfind: (ขโมยมาจากสเตฟาน)

find . -type f ! -size 0 -exec bash -c '
    for f do
        [ "$((`stat -c "%b*%B-%s" -- "$f"`))" -lt 0 ] && printf "%s\n" "$f";
    done' {} +

คุณมักจะใส่สิ่งนี้ในเชลล์สคริปต์แทนจากนั้นเรียกใช้สคริปต์เชลล์

find . -type f ! -size 0 -exec ./sparsetest.sh {} +

ซึ่งอาจไม่ทำงานหากบล็อกกระจัดกระจายไม่เพียงพอที่จะครอบคลุมค่าใช้จ่ายของบล็อกทางอ้อมในระบบไฟล์แบบดั้งเดิมตัวอย่างเช่นหากการบีบอัดแทนที่จะเป็นแบบกระจายจะลดปริมาณพื้นที่ที่จัดสรร
Stéphane Chazelas

แน่นอนว่า; SEEK_HOLEมันเป็นปัญหาเหมือนกันเพราะมันไม่ได้รับการสนับสนุนจากหลายแพลตฟอร์ม / ระบบไฟล์ ในลีนุกซ์คุณสามารถใช้FIEMAP/ FIBMAP, แต่FIBMAPโดยเฉพาะอย่างยิ่งช้าอย่างน่ากลัว ... ดูเหมือนว่าจะไม่เป็นวิธีที่ดี
frostschutz

นอกจากนี้วิธีการเหล่านี้จำนวนมากต้องการให้ซิงค์ไฟล์ก่อน
frostschutz

ขอบคุณ แต่นั่นไม่ได้ตอบคำถามจริงๆ ฉันไม่ได้ต้องการตรวจสอบว่าไฟล์ใดกระจัดกระจาย แต่เพื่อค้นหาไฟล์กระจัดกระจายทั้งหมดในระบบ
Andrew Ferrier

1
@AndrewFerrier ขอโทษผมคิดว่าผมคิดว่ามันเป็นเรื่องเล็ก ๆ น้อยพอที่จะห่อนี้ในหรือfor file in * findหากคุณสามารถทดสอบไฟล์เดียวคุณสามารถทดสอบไฟล์ทั้งหมด ... แม้ว่าคุณจะต้องแยกไดเรกทอรีด้วยวิธีนี้
frostschutz

3

คำตอบของ Stephane Chazelas ไม่ได้คำนึงถึงความจริงที่ว่าไฟล์ sparse ที่มีพารามิเตอร์ find% S รายงานอัตราส่วนเป็นตัวเลขทศนิยมเช่น

9.31323e-09:./somedir/sparsefile.bin

เหล่านี้สามารถพบได้ในนอกเหนือจาก

find . -type f ! -size 0 -printf '%S:%p\0' |
   sed -zn '/^\(0[^:]*:\)\|\([0-9.]\+e-.*:\)/p' |
   tr '\0' '\n'

1

สคริปต์สั้น ๆ ที่ฉันเขียนในขณะที่พยายามค้นหาตำแหน่งของรูในไฟล์:

#!/usr/bin/python3
import os
import sys
import errno

def report(fname):
    fd = os.open(fname, os.O_RDONLY)
    len = os.lseek(fd, 0, os.SEEK_END)
    offset = 0
    while offset < len:
        start = os.lseek(fd, offset, os.SEEK_HOLE)
        if start == len:
            break
        try:
            offset = os.lseek(fd, start, os.SEEK_DATA)
        except OSError as e:
            if e.errno == errno.ENXIO:
                offset = len
            else:
                raise
        print(f'found hole between 0x{start:08X} and 0x{offset:08X} ({offset - start} bytes)')

if __name__ == '__main__':
    for name in sys.argv[1:]:
        report(name)

สิ่งนี้พิมพ์สิ่งที่ชอบ:

$ echo -n 'a' >zeros; truncate -s $((4096*4)) zeros; test/report-holes.py zeros
found hole between 0x00001000 and 0x00004000 (12288 bytes)

ไม่ตอบคำถามของฉันเมื่อฉันกำลังมองหาไฟล์ที่กระจัดกระจายไม่ใช่ช่องโหว่ในไฟล์ที่ระบุ แต่ยังเป็นสคริปต์ที่มีประโยชน์ / เกี่ยวข้อง ขอบคุณ upvoted
Andrew Ferrier
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.