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.