Sui sistemi (e file system) che supportano il SEEK_HOLE
lseek
flag (come farebbe Ubuntu 12.04 su ext4) e assumendo che il valore SEEK_HOLE
sia 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 perl
e 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 %S
riportare 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_HOLE
o file system dove SEEK_HOLE
non è 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 find
espressa la scarsità come ad esempio 3.2e-05. Grazie alla risposta di @ flashydave per averlo portato alla mia attenzione)