희소 파일을 찾고 계십니까?

희소 파일을 찾고 계십니까?

내 시스템이나 특정 디렉터리 트리에서 모든 스파스 파일을 쉽게 찾을 수 있는 방법이 있습니까?

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

편집하다: 명확히 말하면 개별 파일의 희소성 상태를 확인하는 것이 아니라 희소성 파일을 찾고 있습니다.

답변1

이 플래그를 지원하는 SEEK_HOLE lseek시스템(및 파일 시스템)(예: ext4의 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입니다. 내부에 휴대할 수 없는 물건은 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보고 해야 합니다.희소성파일의. 그것은 사용한다프로스트슈츠의 답변디스크 사용량과 파일 크기의 비율을 고려하기 때문에 모든 희소 파일 속성을 보고한다고 보장할 수 없습니다(예: 파일 시스템 수준에서 압축이 수행되는 경우 또는 홀 절약이 파일 시스템 인프라 오버헤드를 보상하지 못하는 경우 또는 대용량 확장 파일의 경우) ), 구현되지 않은 시스템이나 구현되지 않은 SEEK_HOLE파일 시스템 에서는 작동합니다 . SEEK_HOLE여기에 GNU 도구가 있습니다:

LC_ALL=C find . -type f ! -size 0 -printf '%S:%p\0' |
  LC_ALL=C awk -v RS='\0' -F : '$1 < 1 {sub(/^[^:]*:/, ""); print}'

find(이 답변의 이전 버전은 3.2e-05와 같이 희소성을 표현할 때 제대로 작동하지 않았습니다 . 감사합니다.@flashydave의 답변내 주목을 끌었다. 로케일 기준 대신 LC_ALL=C10진수 기준이 필요합니다 (모든 구현이 로케일 설정을 존중하는 것은 아닙니다)..awk

답변2

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

답변3

%S다음 형식의 스파스 파일을 찾을 수 있습니다 find.

# find / -type f -printf "%S\t%p\n" | gawk '$1 < 1.0 {print}'
0.0139994       /var/log/lastlog
0.959592        /usr/lib/locale/locale-archive
...

이 기사에서 발견된 내용: https://www.thegeekdiary.com/how-to-find-all-the-sparse-file-in-linux/

답변4

취약점이 파일의 어디에 있는지 알아내려고 노력하면서 작성한 짧은 스크립트는 다음과 같습니다.

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

관련 정보