Tìm tập tin thưa thớt?


19

Có cách nào đơn giản để tìm tất cả các tệp thưa thớt trên hệ thống của tôi hoặc trong một cây thư mục cụ thể không?

Nếu nó có liên quan, tôi đang sử dụng zshtrên Ubuntu 12.04, mặc dù câu trả lời Unix-y chung hơn cho bash / sh, chẳng hạn, sẽ ổn.

Chỉnh sửa : để làm rõ, tôi đang tìm kiếm các tệp thưa thớt, không kiểm tra trạng thái thưa thớt của một tệp.



2
Điều gì khiến bạn cảm thấy việc tìm kiếm các tệp thưa thớt không liên quan đến việc kiểm tra trạng thái thưa thớt của từng tệp?
jlliagre

Câu trả lời:


11

Trên các hệ thống (và hệ thống tệp) hỗ trợ SEEK_HOLE lseekcờ (như Ubuntu 12.04 của bạn trên ext4) và giả sử giá trị SEEK_HOLElà 4 như trên 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

Cú pháp shell đó là POSIX. Các công cụ không di động trong đó là perlvà đó SEEK_HOLE.

lseek(SEEK_HOLE)tìm kiếm điểm bắt đầu của lỗ đầu tiên trong tệp hoặc cuối tệp nếu không tìm thấy lỗ. Ở trên chúng ta biết tệp không thưa thớt khi lseek(SEEK_HOLE)đưa chúng ta đến cuối tệp (đến cùng một nơi với lseek(SEEK_END)).

Nếu bạn muốn liệt kê các tập tin thưa thớt:

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(kể từ phiên bản 4.3.3) -printf %Sphải báo cáo độ thưa của tệp. Nó có cách tiếp cận giống như câu trả lời của frostschutz ở chỗ nó lấy tỷ lệ sử dụng đĩa so với kích thước tệp, do đó không được đảm bảo báo cáo tất cả các tệp thưa thớt (như khi nén ở cấp hệ thống tệp hoặc nơi không gian được lưu bởi các lỗ không bù cho chi phí cơ sở hạ tầng hệ thống tập tin hoặc các thuộc tính mở rộng lớn), nhưng sẽ hoạt động trên các hệ thống không có SEEK_HOLEhoặc hệ thống tệp SEEK_HOLEkhông được triển khai. Ở đây có các công cụ GNU:

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

(lưu ý rằng phiên bản trước của câu trả lời này không hoạt động chính xác khi findthể hiện độ thưa như ví dụ 3.2e-05. Cảm ơn câu trả lời của @ flashydave đã khiến tôi chú ý)


Nhận xét tương tự như trên; Tôi đang tìm cách để tìm tất cả các tệp thưa thớt, không kiểm tra một tệp cụ thể.
Andrew Ferrier

1
Có lẽ findcũng nên loại trừ hoàn toàn các tệp 0 byte?
frostschutz

@frostschutz, điểm tốt, câu trả lời cập nhật.
Stéphane Chazelas

Đẹp tìm với find -printf '%S'! :-)
frostschutz

1
@Brian, thay thế trlệnh bằngxargs -r0 rm -f
Stéphane Chazelas

8

Một tệp thường thưa thớt khi số khối được phân bổ nhỏ hơn kích thước tệp (ở đây sử dụng GNU statnhư tìm thấy trên Ubuntu, nhưng hãy cẩn thận với các hệ thống khác có thể có các triển khai không tương thích stat).

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

Biến thể với find: (bị đánh cắp từ Stephane)

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

Thay vào đó, bạn thường đặt tập lệnh này vào tập lệnh shell, sau đó thực thi tập lệnh shell.

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

Điều đó có thể không hoạt động nếu các khối thưa thớt không đủ để chi trả cho phần trên của các khối gián tiếp trong các hệ thống tệp truyền thống, ví dụ, nếu nén thay vì thưa thớt sẽ làm giảm dung lượng được phân bổ.
Stéphane Chazelas

Chắc chắn rồi; SEEK_HOLEmặc dù cũng có vấn đề, vì nó không được hỗ trợ bởi nhiều nền tảng / hệ thống tập tin. Trong Linux, bạn cũng có thể sử dụng FIEMAP/ FIBMAP, nhưng FIBMAPđặc biệt là chậm khủng khiếp ... dường như không có cách nào tốt.
frostschutz

Ngoài ra rất nhiều phương thức này yêu cầu tệp phải được đồng bộ hóa trước.
frostschutz

Cảm ơn. Điều đó không thực sự trả lời câu hỏi, mặc dù. Tôi không muốn kiểm tra xem một tập tin cụ thể có thưa thớt không, nhưng để tìm tất cả các tập tin thưa thớt trên hệ thống.
Andrew Ferrier

1
@AndrewFerrier xin lỗi, tôi đoán tôi nghĩ nó đủ tầm thường để bọc cái này trong một for file in *hoặc find. Nếu bạn có thể kiểm tra một tệp duy nhất, bạn có thể kiểm tra tất cả các tệp ... mặc dù bạn phải loại trừ các thư mục bằng phương pháp này.
frostschutz

3

Câu trả lời của Stephane Chazelas ở trên không tính đến thực tế là một số tệp thưa thớt với tham số find% S báo cáo tỷ lệ dưới dạng số dấu phẩy động như

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

Chúng có thể được tìm thấy ngoài

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

1

Một đoạn script ngắn tôi đã viết trong khi cố gắng tìm ra vị trí của các lỗ hổng trong tệp:

#!/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)

Điều này in những thứ như:

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

Không trả lời câu hỏi của tôi vì tôi đang tìm kiếm các tệp thưa thớt, không phải các lỗ hổng trong một tệp cụ thể, nhưng vẫn là một tập lệnh hữu ích / có liên quan. Cảm ơn. Nâng cao.
Andrew Ferrier
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.