查找稀疏文件?


19

有没有一种直接的方法可以找到系统上或特定目录树中的所有稀疏文件?

如果相关,我将zsh在Ubuntu 12.04上使用,尽管例如,对于bash / sh而言,更通用的Unix-y回答可能会很好。

编辑:澄清一下,我正在寻找稀疏文件,而不是检查单个文件的稀疏状态。



2
是什么让您觉得搜索稀疏文件并不涉及检查单个文件的稀疏状态?
jlliagre

Answers:


11

在支持该SEEK_HOLE lseek标志的系统(和文件系统)上(例如ext4上的Ubuntu 12.04将支持该标志),并假定Linux上的值SEEK_HOLE是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的回答引起了我的注意)


与上述相同的评论;我正在寻找一种方法来查找所有稀疏文件,而不是检查特定文件。
安德鲁·费里尔

1
也许find还应该彻底排除0字节文件?
弗罗斯特斯

@frostschutz,要点,答案已更新。
斯特凡Chazelas

很高兴找到find -printf '%S'!:-)
frostschutz

1
@布赖恩,更换tr用命令xargs -r0 rm -f
斯特凡Chazelas

8

当分配的块数小于文件大小时,文件通常是稀疏的(此处使用的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' {} +

通常,您通常将其放在shell脚本中,然后执行shell脚本。

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

例如,如果稀疏块不足以覆盖传统文件系统中的间接块的开销,则这可能不起作用,例如,压缩而不是稀疏会减少分配的空间量。
斯特凡Chazelas

当然; SEEK_HOLE但是同样存在问题,因为许多平台/文件系统都不支持它。在Linux中,您也可以使用FIEMAP/ FIBMAP,但是FIBMAP特别慢,这似乎不是一个好方法。
弗罗斯特斯

此外,许多这些方法都要求首先同步文件。
弗罗斯特斯

谢谢。但是,这并不能真正回答问题。我不是要检查特定文件是否稀疏,而是要查找系统上所有稀疏文件。
安德鲁·费里尔

1
@AndrewFerrier抱歉,我想我认为将其包装在a for file in *或中非常简单find。如果可以测试单个文件,则可以测试所有文件...尽管您必须使用此方法排除目录。
弗罗斯特斯

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)

在寻找稀疏文件时,没有回答我的问题,不是寻找特定文件中的漏洞,而是一个有用/相关的脚本。谢谢。已投票。
安德鲁·费里尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.