Trovare file sparsi?


19

Esiste un modo semplice per trovare tutti i file sparsi sul mio sistema o in un determinato albero di directory?

Se è pertinente, sto usando zshUbuntu 12.04, anche se una risposta Unix-y più generica per bash / sh, per esempio, andrebbe bene.

Modifica : per chiarire, sto cercando di cercare file sparsi, non controllare lo stato di scarsità di un singolo.



2
Cosa ti fa sentire la ricerca di file sparsi non comporta il controllo dello stato di sparseness dei singoli?
jlliagre,

Risposte:


11

Sui sistemi (e file system) che supportano il SEEK_HOLE lseekflag (come farebbe Ubuntu 12.04 su ext4) e assumendo che il valore SEEK_HOLEsia 4 come su 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

La sintassi della shell è POSIX. Le cose non portatili in esso sono perle quello SEEK_HOLE.

lseek(SEEK_HOLE)cerca l'inizio del primo buco nel file o la fine del file se non viene trovato alcun buco. Sopra sappiamo che il file non è scarso quando lseek(SEEK_HOLE)ci porta alla fine del file (nella stessa posizione di lseek(SEEK_END)).

Se si desidera elencare i file sparsi:

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}' {} +

La GNU find(dalla versione 4.3.3) deve -printf %Sriportare la scarsità di un file. Adotta lo stesso approccio della risposta di frostschutz in quanto prende il rapporto tra uso del disco e dimensioni del file, quindi non è garantito che riporti tutti i file sparsi (come quando c'è compressione a livello di filesystem o dove lo spazio salvato dai buchi non lo fa compensare l'overhead dell'infrastruttura del filesystem o gli attributi estesi di grandi dimensioni), ma funzionerebbe su sistemi che non hanno SEEK_HOLEo file system dove SEEK_HOLEnon è implementato. Qui con gli strumenti GNU:

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

(nota che una versione precedente di questa risposta non funzionava correttamente quando findespressa la scarsità come ad esempio 3.2e-05. Grazie alla risposta di @ flashydave per averlo portato alla mia attenzione)


Stesso commento di cui sopra; Sto cercando un modo per trovare tutti i file sparsi, non controllare un determinato file.
Andrew Ferrier,

1
Forse finddovresti anche escludere completamente i file a 0 byte?
frostschutz,

@frostschutz, buon punto, risposta aggiornata.
Stéphane Chazelas,

Bello trovare con il find -printf '%S'! :-)
frostschutz

1
@Brian, sostituisci il trcomando conxargs -r0 rm -f
Stéphane Chazelas il

8

Un file di solito è scarso quando il numero di blocchi allocati è inferiore alla dimensione del file (qui usando GNU statcome si trova su Ubuntu, ma attenzione agli altri sistemi potrebbero avere implementazioni incompatibili di stat).

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

Variante con find: (rubato a 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' {} +

Di solito lo metti in uno script di shell, quindi esegui lo script di shell.

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

Ciò potrebbe non funzionare se i blocchi sparsi non sono sufficienti a coprire l'overhead dei blocchi indiretti nei file system tradizionali, ad esempio, se la compressione anziché la scarsità sta riducendo la quantità di spazio allocato.
Stéphane Chazelas,

Sicuro; SEEK_HOLEè altrettanto problematico, poiché non è supportato da molte piattaforme / filesystem. In Linux puoi anche usare FIEMAP/ FIBMAP, ma FIBMAPin particolare è terribilmente lento ... non sembra proprio essere un buon modo.
frostschutz,

Inoltre, molti di questi metodi richiedono prima la sincronizzazione del file.
frostschutz,

Grazie. Questo non risponde davvero alla domanda, però. Non sto cercando di verificare se un determinato file è scarso, ma per trovare tutti i file sparsi sul sistema.
Andrew Ferrier,

1
@AndrewFerrier scusa, immagino di aver pensato che fosse abbastanza banale avvolgerlo in un for file in *o find. Se riesci a provare un singolo file, puoi provare tutti i file ... anche se devi escludere directory con questo metodo.
frostschutz,

3

La risposta di Stephane Chazelas non tiene conto del fatto che alcuni file sparsi con il parametro find% S riportano il rapporto come numeri in virgola mobile come

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

Questi possono essere trovati in aggiunta con

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

1

Una breve sceneggiatura che ho scritto mentre cercavo di scoprire quali sono le posizioni dei buchi in un file:

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

Questo stampa cose come:

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

Non risponde alla mia domanda mentre cercavo file sparsi, non i buchi in un file specifico, ma comunque uno script utile / pertinente. Grazie. Upvoted.
Andrew Ferrier,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.