我需要检查哪些日志文件包含特定数据.
对于init我只需执行以下操作:
'-query-data-' zgrep -m 1 '^20140320-04' 20140320-0{3,4}*gz
但是如何对最后一行执行相同操作而不处理整个文件,就像使用zcat(太重)一样:
zcat foo.gz | tail -1
附加信息,这些日志是使用它的初始记录的数据时间创建的,所以如果我想在14:00:00查询日志,我也必须在14:00:00之前创建的文件中搜索,作为文件将在13:50:00创建,在14:10:00关闭.
像dictzip,BGZF和csio这样的项目在gzip压缩数据中以不同的间隔添加sync flush points,允许您在程序中查找该额外信息.虽然它存在于标准中,但vanilla gzip不会默认或通过选项添加此类标记.
由这些随机访问友好的实用程序压缩的文件由于标记本身略大(可能是2-20%),但完全支持使用gzip或其他不知道这些标记的实用程序进行解压缩.
您可以在这个关于random access in various compression formats的问题上了解更多信息.
还有一个由Peter Cock撰写的“Blasted Bioinformatics”博客,其中有几个关于这个主题的帖子,包括:
> BGZF – Blocked,Bigger & Better GZIP! – 随机访问gzip(如dictzip)
> Random access to BZIP2? – 调查(结果:无法完成,但我在下面这样做)
> Random access to blocked XZ format (BXZF) – xz具有改进的随机访问支持
用xz进行实验
xz
(LZMA压缩格式)实际上在每个块级别上具有随机访问支持,但是您将只获得具有默认值的单个块.
文件创建
xz可以将多个归档连接在一起,在这种情况下,每个归档都有自己的块. GNU split
可以轻松完成:
split -b 50M --filter 'xz -c' big.log > big.log.sp.xz
这告诉split将big.log分解为50MB块(压缩前)并通过xz -c运行每个块,它将压缩块输出到标准输出.然后,我们将该标准输出收集到名为big.log.sp.xz的单个文件中.
要在没有GNU的情况下执行此操作,您需要一个循环:
split -b 50M big.log big.log-part for p in big.log-part*; do xz -c $p; done > big.log.sp.xz rm big.log-part*
解析
您可以使用xz –verbose –list FILE.xz获取块偏移列表.如果你想要最后一个块,你需要它的压缩大小(第5列)加上36个字节的开销(通过将大小与hd big.log.sp0.xz | grep 7zXZ进行比较找到).使用tail -c和xz管道获取该块.由于上面的问题想要文件的最后一行,我然后通过tail -n1管道:
SIZE=$(xz --verbose --list big.log.sp.xz |awk 'END { print $5 + 36 }') tail -c $SIZE big.log.sp.xz |unxz -c |tail -n1
边注
版本5.1.1引入了对–block-size标志的支持:
xz --block-size=50M big.log
但是,我无法提取特定块,因为它不包括块之间的完整标头.我怀疑从命令行这是非常重要的.
用gzip进行实验
gzip还支持连接.我(简要地)试图模仿gzip的这个过程而没有任何运气. gzip –verbose –list没有提供足够的信息,看起来标题太多变化,无法找到.
这将需要添加同步刷新点,并且由于它们的大小因先前压缩中的最后一个缓冲区的大小而异,这在命令行上很难做到(使用dictzip或之前讨论的其他工具).
我做了apt-get install dictzip和dictzip一起玩,但只是一点点.如果没有参数,它就无法工作,创建了一个(大量!).dz存档,dictunzip和gunzip都不能理解.
用bzip2进行实验
bzip2有我们可以找到的标题.这仍然有点凌乱,但它的确有效.
创建
这就像上面的xz程序:
split -b 50M --filter 'bzip2 -c' big.log > big.log.sp.bz2
我应该注意到这比xz慢得多(bzip2为48分钟,xz为17分钟,xz为0分钟为1分钟)以及相当大(bzip2为97M,xz为0M为25M,xz为15M),至少我的测试日志文件.
解析
这有点难,因为我们没有漂亮的索引.我们必须猜测要去哪里,我们必须在扫描过程中犯错误,但是如果有大量文件,我们仍然可以节省I / O.
我对这个测试的猜测是50000000(原始的52428800中,一个悲观的猜测,对于例如H.264电影来说并不是悲观的.)
GUESS=50000000 LAST=$(tail -c$GUESS big.log.sp.bz2 \ |grep -abo 'BZh91AY&SY' |awk -F: 'END { print '$GUESS'-$1 }') tail -c $LAST big.log.sp.bz2 |bunzip2 -c |tail -n1
这只需要最后的5000万字节,找到最后一个BZIP2标头的二进制偏移量,从猜测大小中减去它,然后从文件末尾拉出那么多字节.只是那部分被解压缩并抛入尾部.
因为这必须两次查询压缩文件并进行额外扫描(grep调用寻找标题,检查整个猜测的空间),这是一个次优的解决方案.另请参阅以下有关bzip2的缓慢程度的部分.
透视
鉴于xz有多快,它很容易成为最好的选择;使用其最快的选项(xz -0)压缩或解压缩的速度非常快,并且在我测试的日志文件中创建比gzip或bzip2更小的文件.其他测试(以及在线的各种来源)表明,在所有情况下,xz-0优于bzip2.
————— No Random Access —————— ——————— Random Access ——————— FORMAT SIZE RATIO WRITE READ SIZE RATIO WRITE SEEK ————————— ————————————————————————————— ————————————————————————————— (original) 7211M 1.0000 - 0:06 7211M 1.0000 - 0:00 bzip2 96M 0.0133 48:31 3:15 97M 0.0134 47:39 0:00 gzip 79M 0.0109 0:59 0:22 dictzip 605M 0.0839 1:36 (fail) xz -0 25M 0.0034 1:14 0:12 25M 0.0035 1:08 0:00 xz 14M 0.0019 16:32 0:11 14M 0.0020 16:44 0:00
时序测试不全面,我没有任何平均值,磁盘缓存正在使用中.他们看起来仍然正确;分裂加上启动145个压缩实例而不仅仅是一个压缩实例的开销非常小(如果它允许其他非多线程实用程序使用多个线程,这甚至可能是净增益).