В системах (и файловых системах), поддерживающих SEEK_HOLE lseekфлаг (как, например, ваша Ubuntu 12.04 на ext4) и предполагающих значение для SEEK_HOLE4, как в 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
Этот синтаксис оболочки - POSIX. Непереносимые вещи в нем есть perlи то SEEK_HOLE.
lseek(SEEK_HOLE)ищет начало первого отверстия в файле или конец файла, если отверстие не найдено. Выше мы знаем, что файл не редкий, когда он lseek(SEEK_HOLE)переносит нас в конец файла (в то же место, что и lseek(SEEK_END)).
Если вы хотите перечислить разреженные файлы:
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(начиная с версии 4.3.3) должен -printf %Sсообщать о редкости файла. Он использует тот же подход, что и ответ frostschutz, в том смысле, что он принимает соотношение использования диска и размера файла, поэтому не гарантируется, что он сообщает обо всех разреженных файлах (например, когда есть сжатие на уровне файловой системы или когда пространство, сэкономленное дырами, не компенсировать накладные расходы на инфраструктуру файловой системы или большие расширенные атрибуты), но будет работать в системах, которые не имеют, SEEK_HOLEили в файловых системах, где SEEK_HOLEэто не реализовано. Здесь с инструментами GNU:
find . -type f ! -size 0 -printf '%S:%p\0' |
awk -v RS='\0' -F : '$1 < 1 {sub(/^[^:]*:/, ""); print}'
(обратите внимание, что более ранняя версия этого ответа не работала должным образом, когда findвыражалась редкость, как, например, 3.2e-05. Спасибо ответу @ flashydave за то, что он привлек мое внимание)