스파 스 파일을 찾으십니까?


19

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

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

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



2
스파 스 파일을 검색한다고 느끼게 만드는 것은 개별 파일의 희소 상태를 확인하는 것과 관련이 없습니까?
jlliagre

답변:


11

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의 답변을 내 관심을 가져 용)


위와 같은 의견; 특정 파일을 확인하지 않고 모든 스파 스 파일을 찾는 방법을 찾고 있습니다.
Andrew Ferrier

1
아마도 find0 바이트 파일을 완전히 제외시켜야합니까?
frostschutz

@frostschutz, 좋은 지적, 답변이 업데이트되었습니다.
Stéphane Chazelas

와 좋은 찾기 find -printf '%S'! :-)
frostschutz

1
@Brian, 다음 tr명령으로 대체하십시오xargs -r0 rm -f
Stéphane Chazelas

8

할당 된 블록의 수가 파일 크기보다 작을 때 파일은 일반적으로 드문 경우입니다 (여기서는 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 {} +

예를 들어 희소 대신 압축이 할당 된 공간의 양을 줄이는 경우와 같이, 희소 블록이 전통적인 파일 시스템에서 간접 블록의 오버 헤드를 처리하기에 충분하지 않은 경우에는 작동하지 않을 수 있습니다.
Stéphane Chazelas

확실한; SEEK_HOLE많은 플랫폼 / 파일 시스템에서 지원하지 않기 때문에 문제가됩니다. 리눅스에서는 FIEMAP/ 를 사용할 수도 FIBMAP있지만 FIBMAP특히 느리게 느리다. 좋은 방법은 아닌 것 같다.
frostschutz

또한 이러한 많은 방법을 사용하려면 파일을 먼저 동기화해야합니다.
frostschutz

감사. 그러나 그것은 실제로 질문에 대답하지 않습니다. 특정 파일이 스파 스인지 확인하지 않고 시스템에서 모든 스파 스 파일을 찾습니다.
Andrew Ferrier

1
@AndrewFerrier 죄송합니다, for file in *또는에 이것을 감싸기에 충분하다고 생각합니다 find. 단일 파일을 테스트 할 수 있으면 모든 파일을 테스트 할 수 있지만이 방법으로 디렉토리를 제외해야합니다.
frostschutz

3

위의 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'

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)

특정 파일의 구멍이 아니라 유용한 / 관련 스크립트 인 스파 스 파일을 찾을 때 내 질문에 대답하지 않습니다. 감사. 공감.
Andrew Ferrier
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.