bash – 如何zgrep没有尾部的gz文件的最后一行

前端之家收集整理的这篇文章主要介绍了bash – 如何zgrep没有尾部的gz文件的最后一行前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这是我的问题,我有一组大的gz日志文件,该行中的第一个信息是日期时间文本,例如:2014-03-20 05:32:00.

我需要检查哪些日志文件包含特定数据.
对于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,BGZFcsio这样的项目在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个压缩实例而不仅仅是一个压缩实例的开销非常小(如果它允许其他非多线程实用程序使用多个线程,这甚至可能是净增益).

猜你在找的Bash相关文章