내 시스템 또는 특정 디렉토리 트리에서 모든 스파 스 파일을 찾는 간단한 방법이 있습니까?
관련이 있다면 zsh
Ubuntu 12.04에서 사용하고 있지만 bash / sh에 대한 일반적인 Unix-y 대답은 괜찮을 것입니다.
편집 : 명확히하기 위해, 희소 파일을 검색하려고하지만 단일 파일의 희소 상태를 확인하지 않습니다.
답변
SEEK_HOLE
lseek
ext4의 Ubuntu 12.04와 같이 플래그를 지원하고 SEEK_HOLE
Linux에서와 같이 값 이 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
의 희소성 을보고해야 합니다. 디스크 사용량과 파일 크기의 비율을 취한다는 점에서 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의 답변을 내 관심을 가져 용)
답변
할당 된 블록의 수가 파일 크기보다 작을 때 파일은 일반적으로 드문 경우입니다 (여기서는 stat
Ubuntu에있는 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)