这是我的问题,我有一组大的gz日志文件,该行中的第一个信息是日期时间文本,例如:2014-03-20 05:32:00。

我需要检查哪些日志文件集包含特定数据。
对于初始化,我只需执行以下操作:

           '-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关闭。

最佳答案

最简单的解决方案是更改日志轮换以创建较小的文件。

第二个最简单的解决方案是使用支持随机访问的压缩工具。

dictzipBGZFcsio之类的项目在gzip压缩数据中的各个间隔处都添加了sync flush points,使您可以在程序中寻找有关该额外信息的信息。尽管标准中存在它,但香草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进行实验

xzLZMA压缩格式)实际上在每个块级别上具有随机访问支持,但是您只会获得具有默认值的单个块。

档案建立

xz可以将多个档案串联在一起,在这种情况下,每个档案都有自己的块。 GNU split可以很容易地做到这一点:



split -b 50M --filter 'xz -c' big.log > big.log.sp.xz


这告诉splitbig.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玩,但是只有一点点。没有参数就无法工作,创建一个.dzdictunzip都无法理解的(大量!)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 -0为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标头的二进制偏移量,从猜测大小中减去它,然后从文件末尾拉出那么多字节。只是将那部分解压缩并放入tail中。

因为这必须两次查询压缩文件并进行一次额外的扫描(grep调用将查找标题,该标题将检查整个猜测的空间),所以这是次佳的解决方案。另请参阅以下有关bzip2实际速度的部分。



透视

鉴于xz有多快,它很容易成为最佳选择。使用其最快的选项(xz -0)可以非常快速地进行压缩或解压缩,并在我正在测试的日志文件上创建比gzipbzip2小的文件。其他测试(以及各种在线资源)表明,在所有情况下xz -0均优于bzip2

—————禁止随机访问——————————————随机访问————————
格式大小比率写读大小比率写
—————————————————————————————————————————————————————— ——————————————————
(原始)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(失败)
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


时序测试并不全面,我没有平均任何东西,并且正在使用磁盘缓存。不过,它们看起来正确。 split加上启动145个压缩实例的开销很小,而不仅仅是启动一个实例(如果它允许其他非多线程实用程序使用多个线程,则甚至可能是纯收益)。

关于bash - 如何zgrep没有尾部的gz文件的最后一行,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22533060/

10-11 04:24