[unix] 스파 스 파일을 찾으십니까?

내 시스템 또는 특정 디렉토리 트리에서 모든 스파 스 파일을 찾는 간단한 방법이 있습니까?

관련이 있다면 zshUbuntu 12.04에서 사용하고 있지만 bash / sh에 대한 일반적인 Unix-y 대답은 괜찮을 것입니다.

편집 : 명확히하기 위해, 희소 파일을 검색하려고하지만 단일 파일의 희소 상태를 확인하지 않습니다.



답변

SEEK_HOLE lseekext4의 Ubuntu 12.04와 같이 플래그를 지원하고 SEEK_HOLELinux에서와 같이 값 이 4 라고 가정하는 시스템 및 파일 시스템 에서 :

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입니다. 거기에 비 휴대용 물건은 perlSEEK_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의 답변을 내 관심을 가져 용)


답변

할당 된 블록의 수가 파일 크기보다 작을 때 파일은 일반적으로 드문 경우입니다 (여기서는 statUbuntu에있는 GNU 를 사용 하지만 다른 시스템은 호환되지 않는 구현을 가질 수 있음 stat).

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

변형 find: (스테판에서 도난 당함)

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 {} +


답변

위의 Stephane Chazelas 답변은 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'


답변

파일에서 구멍의 위치가 무엇인지 찾으려고 노력하면서 작성한 짧은 스크립트 :

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


답변