В системах (и файловых системах), поддерживающих SEEK_HOLE
lseek
флаг (как, например, ваша Ubuntu 12.04 на ext4) и предполагающих значение для SEEK_HOLE
4, как в 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 за то, что он привлек мое внимание)