Знаходження розріджених файлів?


19

Чи є простий спосіб знайти всі розріджені файли в моїй системі або в певному дереві каталогів?

Якщо це доречно, я використовую zshUbuntu 12.04, хоча більш загальна відповідь Unix-y для, наприклад, bash / sh, буде добре.

Редагувати : щоб уточнити, я хочу шукати розріджені файли, а не перевіряти стан розрідженості жодного.



2
Чому ви відчуваєте, що пошук розріджених файлів не передбачає перевірки статусу обмеженості окремих?
jlliagre

Відповіді:


11

У системах (і файлових системах), що підтримують 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 за те, що я звернув її до мене)


Той самий коментар, що і вище; Я шукаю спосіб знайти всі розріджені файли, а не перевірити конкретний файл.
Ендрю Фер’є

1
Можливо, findслід також виключати 0-байт-файли прямо?
frostschutz

@frostschutz, хороший пункт, відповідь оновлена.
Стефан Шазелас

Приємна знахідка з find -printf '%S'! :-)
frostschutz

1
@Brian, замініть trкоманду наxargs -r0 rm -f
Stéphane Chazelas

8

Файл, як правило, є рідким, коли кількість виділених блоків менша за розмір файлу (тут використовується GNU, statяк знайдено в Ubuntu, але будьте обережні, що інші системи можуть мати несумісні реалізації stat).

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

Варіант find: (вкрадено у 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' {} +

Зазвичай ви ставите це замість сценарію оболонки, а потім виконуйте сценарій оболонки.

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

Це може не спрацювати, якщо розріджених блоків недостатньо для покриття накладних витрат непрямих блоків у традиційних файлових системах, наприклад, якщо стиснення замість розрідженості зменшує кількість виділеного простору.
Стефан Шазелас

Впевнений; SEEK_HOLEнастільки ж проблематично, оскільки не підтримується багатьма платформами / файловими системами. У Linux ви також можете використовувати FIEMAP/ FIBMAP, але, FIBMAPзокрема, жахливо повільно ... просто це не здається хорошим способом.
frostschutz

Також багато цих методів вимагають синхронізації файлів спочатку.
frostschutz

Спасибі. Але це насправді не відповідає на питання. Я не хочу перевіряти, чи певний файл є рідким, але щоб знайти всі розріджені файли в системі.
Ендрю Фер’є

1
@AndrewFerrier вибачте, я думаю, я вважав, що це досить тривіально, щоб обернути це в for file in *або find. Якщо ви можете протестувати один файл, ви можете протестувати всі файли ... хоча вам доведеться виключати каталоги цим методом.
frostschutz

3

Відповідь Стефана Шазеласа вище не враховує той факт, що деякі розріджені файли з параметром find% S повідомляють про співвідношення як числа з плаваючою комою, як

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

Їх можна знайти на додаток до

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

1

Короткий сценарій, який я написав, намагаючись з'ясувати, які місця розміщення дірок у файлі:

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

Це друкує такі речі, як:

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

Не відповідає на моє запитання, коли я шукав розріджені файли, не дірки у певному файлі, але все-таки корисний / відповідний сценарій. Спасибі. Отримано.
Ендрю Фер’є
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.