Seyrek dosyalar mı arıyorsunuz?


19

Sistemimdeki veya belirli bir dizin ağacındaki tüm seyrek dosyaları bulmanın kolay bir yolu var mı?

İlgili ise, zshörneğin bash / sh için daha genel bir Unix-y yanıtı iyi olsa da Ubuntu 12.04 kullanıyorum .

Düzenleme : açıklığa kavuşturmak için, seyrek dosyaları aramak için arıyorum, tek bir seyrek durumunu kontrol değil.



2
Seyrek dosyaları aramayı hissettiren şey, tek tek dosyaların seyreklik durumunu kontrol etmeyi içermez mi?
jlliagre

Yanıtlar:


11

SEEK_HOLE lseekBayrağı destekleyen sistemlerde (ve ext4'teki Ubuntu 12.04 gibi) ve SEEK_HOLELinux'ta olduğu gibi 4 olduğu varsayıldığında :

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

Bu kabuk sözdizimi POSIX. İçinde taşınabilir olmayan şeyler perlve bu SEEK_HOLE.

lseek(SEEK_HOLE)dosyadaki ilk deliğin başlangıcını veya hiçbir delik bulunmazsa dosyanın sonunu arar . Yukarıda bizi dosyanın lseek(SEEK_HOLE)sonuna götürdüğünde ( seyrek olarak) dosyanın seyrek olmadığını biliyoruz lseek(SEEK_END).

Seyrek dosyaları listelemek istiyorsanız:

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(sürüm 4.3.3'ten beri) bir dosyanın seyrekliğini-printf %S rapor etmek zorundadır . Aynı yaklaşımı benimserDisk kullanımının dosya boyutuna oranını alması nedeniyle frostschutz'un cevabı ile benimser , bu nedenle tüm seyrek dosyaları bildirmesi garanti edilmez (dosya sistemi düzeyinde sıkıştırma olduğunda veya deliklerin kaydettiği alanın olmadığı gibi) dosya sistemi altyapısı yükünü veya büyük genişletilmiş öznitelikleri telafi eder), ancak olmayan SEEK_HOLEsistemlerde veya SEEK_HOLEuygulanmayan dosya sistemlerinde çalışır . İşte GNU araçlarıyla:

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

(bu cevabın önceki bir versiyonunun, findörneğin 3.2e-05 gibi seyreklik ifade edildiğinde düzgün çalışmadığını unutmayın. @ flashydave'nin cevabı sayesinde )


Yukarıdaki ile aynı yorum; Belirli bir dosyayı kontrol etmek değil, tüm seyrek dosyaları bulmak için bir yol arıyorum.
Andrew Ferrier

1
Belki findde 0 baytlık dosyaları hariç tutmalı?
frostschutz

@ frostschutz, iyi bir nokta, cevap güncellendi.
Stéphane Chazelas

Güzel bulmak find -printf '%S'! :-)
frostschutz

1
@Brian, trkomutu yerine koyunxargs -r0 rm -f
Stéphane Chazelas

8

Ayrılan blok sayısı dosya boyutundan daha küçük olduğunda bir dosya genellikle seyrektir (burada statUbuntu'da bulunan GNU kullanılır , ancak diğer sistemlerinstat ).

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

Varyant find : (Stephane'den çalındı)

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

Bunu genellikle bir kabuk betiğine koyar ve ardından kabuk betiğini çalıştırırsınız.

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

Seyrek bloklar, örneğin geleneksel dosya sistemlerinde dolaylı blokların ek yükünü karşılamak için yeterli değilse, örneğin seyreklik yerine sıkıştırmanın ayrılan alan miktarını azaltması durumunda bu işe yaramayabilir.
Stéphane Chazelas

Elbette; SEEK_HOLEbirçok platform / dosya sistemi tarafından desteklenmediği için sorunludur. Linux'ta da FIEMAP/ kullanabilirsiniz FIBMAP, ancak FIBMAPözellikle korkunç derecede yavaş ... iyi bir yol gibi görünmüyor.
frostschutz

Ayrıca bu yöntemlerin birçoğu önce dosyanın senkronize edilmesini gerektirir.
frostschutz

Teşekkürler. Yine de bu soruya gerçekten cevap vermiyor. Belirli bir dosyanın seyrek olup olmadığını kontrol etmek için değil, sistemdeki tüm seyrek dosyaları bulmak için arıyorum.
Andrew Ferrier

1
@AndrewFerrier üzgünüm, sanırım bunu bir for file in *veya içine sarmanın önemsiz olduğunu düşündüm find. Tek bir dosyayı test edebiliyorsanız, tüm dosyaları test edebilirsiniz ... ancak bu yöntemi kullanarak dizinleri hariç tutmak zorundasınız.
frostschutz

3

Yukarıdaki Stephane Chazelas cevabı, find% S parametresine sahip bazı seyrek dosyaların, oranı kayan nokta sayıları olarak bildirdiği gerçeğini dikkate almaz.

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

Bunlara ek olarak bulunabilir

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

1

Bir dosyadaki deliklerin yerlerini öğrenmeye çalışırken yazdığım kısa bir senaryo:

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

Bu gibi şeyler yazdırır:

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

Belirli bir dosyadaki delikleri değil, yine de yararlı / alakalı bir komut dosyasını seyrek olarak aradığım için sorumu yanıtlamıyor. Teşekkürler. Upvoted.
Andrew Ferrier
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.