获取巨大的gzip压缩文件的最后一行

时间:2018-06-29 14:36:34

标签: mysql bash shell

在数据库备份过程中,我生成一个文本转储文件。由于数据库很大,转储文件也很大,所以我用gzip压缩了它。压缩是在生成转储时内联完成的(感谢Unix管道!)。

在过程结束时,我通过观察最后一行来检查转储文件的有效性,并检查“转储完成”字符串的存在。在我的脚本中,我通过将最后一行提取到变量中来做到这一点:

str=`zcat ${PATHSAVE}/dumpFull.sql.gz | tail -n1`

由于数据库转储文件很大(当前超过200Gb),因此此最终过程检查需要大量时间(当前超过180分钟)运行。

我正在寻找一种方法来更快地提取.gz文件的最后一行……有人知道吗?

注1:为了说明上下文,我们可以说数据库是MySql社区,备份工具是mysqldump,生成的dumpfile是全文文件。操作系统是CentO。备份脚本是Bash shell脚本。

注意2:我知道Percona xtraBackup,但就我而言,我想针对此特定备份作业使用mysqldump。恢复时间不成问题。

3 个答案:

答案 0 :(得分:4)

这是fifo(管道)和tee命令的工作。进行备份时使用此功能。

mkfifo mypipe
tail mypipe -1 > lastline.txt & mysqldump whatever | tee mypipe | gzip >dump.gz
rm mypipe

这是怎么回事?

mkfifo mypipe将fifo对象放入当前工作目录。它看起来像是您可以同时写入和读取的文件。

tail mypipe -1 >lastline.txt使用tail读取您写入mypipe的内容,并将最后一行保存在文件中。

mysqldump whatever | tee mypipe | gzip >dump.gz执行转储操作,并将输出通过管道传递到tee命令。 Tee将输出写入mypipe ,并将其通过管道传输到gzip

该命令的两个部分之间的&导致两个部分同时运行。

rm mypipe摆脱了fifo对象。

Charles Duffy指出,某些外壳程序(包括bash)具有进程替换功能,因此,如果您使用这些外壳程序之一,则命令可以更简单。

 mysqldump whatever | tee >(tail -1 > lastline.txt ) | gzip >dump.gz

在这种情况下,shell为您创建了自己的管道。

信用:Pipe output to two different commands

答案 1 :(得分:1)

仅通过使用现有验证(使用zcattail)并从stdin中读取而不是从书面中读取,您可以轻松地确定管道中处理的最后一行,而不是从磁盘中确定文件:

mysqldump args | gzip - | tee fullDump.gz | zcat - | tail -n1

这将为您提供未压缩的最后处理行,您可以根据Dump completed字符串检查是否成功。

这很简单,但并不是100%防弹,因为tee极有可能无法完成写入磁盘,但无法完成向stdout的写入:

  

如果对任何成功打开的文件操作数的写操作失败,则对其他成功打开的文件操作数的写操作将继续,并且标准输出应继续,但退出状态应为非零。

     

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tee.html

为了防止这种可能的失败,我们可以简单地修饰一下管道:

mysqldump args | gzip - | { tee foo.gz || echo "fail" | gzip -; } | zcat - | tail -n1

fail退出非0的情况下,我们发出tee作为最后一行。如果您将bash用作shell,则可以交替使用pipefailset -euxo pipefail),如果有任何命令失败(而不仅仅是最后一个命令),这将导致该管道退出非0。 >

答案 2 :(得分:0)

如果您确实要检查压缩文件的完整性,则可以从gz更改并执行类似的操作

# strings used in order to clean up if it gets messy
dd if=dump.compressed.not-gz bs=1m skip=195000 | compress-tool -df | strings | grep 'Dump complete'

编辑: 您也可以在压缩转储时调试gz,在该转储中您已经注入了“ dump complete”字符串并发现了其签名。数据库转储是相似的,因此也许所有转储都相同。如果是这样,只需像上面那样使用grep即可,但不使用compress和strings命令