从大文件开头删除文本的最佳方法

从大文件开头删除文本的最佳方法

我有一个巨大的 MySQL 备份文件(来自 mysqldump),其中的表按字母顺序排列。我的恢复失败了,我想从备份文件中的下一个表继续上次中断的位置。(我已经更正了这个问题,这实际上不是关于 MySQL 恢复等的问题。)

我想要做的是获取我的备份文件,例如backup.sql并修剪文件的开头,直到我看到以下行:

-- Table structure for `mytable`

然后,之后的所有内容都会出现在我的结果文件中,例如backup-secondhalf.sql。由于文件是 bzip2 压缩的,这有点复杂,但这应该不是什么大问题。

我想我可以这样做:

$ bunzip2 -c backup.sql.bz2 | grep --text --byte-offset --only-matching -e '--Table structure for table `mytable`' -m 1

这将为我提供我想要修剪的文件中的字节偏移量取决于。 然后:

$ bunzip2 -c backup.sql.bz2 | dd skip=[number from above] | bzip2 -c > backup-secondhalf.sql.bz2

不幸的是,这需要我对文件运行两次 bunzip2 并读取所有这些字节两次。

有没有办法一次性完成这一切?

我不确定我的 sed-fu 是否足够强大,可以执行“删除所有行直到正则表达式,然后让文件的其余部分通过”的表达式。

这是在 Debian Linux 上,所以我有可用的 GNU 工具。

答案1

bunzip2 -c backup.sql.bz2 | \
  sed -n '/-- Table structure for `mytable`/,$p'

解释:

-n suppress automatic printing of pattern space

地址范围构造:以正则表达式开始

/-- Table structure for  `mytable`/

结尾

$ Match the last line.

命令

p Print the current pattern space.

编辑:取决于你如何转储数据库,你可能有非常长行。GNU sed 可以处理这些行,直到可用内存量达到最大值。

答案2

注意:不是实际答案

因为我有动力解决这个问题现在之后,我继续grep查找我想要的文件中的偏移量;效果很好。

不幸的是,运行dd需要您设置ibs=1,这基本上意味着没有缓冲,而且性能很糟糕。在等待 dd 完成时,我花了一些时间编写自己的定制 C 程序来跳过字节。完成之后,我发现这tail对我来说同样容易:

$ bunzip2 -c restore.sql.bz2 | tail -c +[offset] | bzip2 -c > restore-trimmed.sql.bz2

我说“这没有回答我的问题”是因为它仍然需要两次传递文件:一次是找到我正在寻找的东西的偏移量,另一次是修剪文件。

如果我回到我的自定义程序,我可以实现一个钾通道蛋白在程序的“只读”阶段,然后切换到“读取+写入所有内容”。

答案3

我想知道这样的事情是否能起到作用:

use strict;
use warnings;
use feature 'say';

use IO::Uncompress::Bunzip2 '$Bunzip2Error';

my $file = $ARGV[0] // die "need a file";

my $zh = IO::Uncompress::Bunzip2->new( $file, {
    AutoClose   => 1,
    Transparent => 1,
} ) or die "IO::Uncompress::Bunzip2 failed: $Bunzip2Error\n";

my $trigger = undef;
while ( <$zh> ) {
    chomp;
    $trigger = 1 if $_ eq '-- Dumping data for table `experiments`';
    say if $trigger;
}

因此基本上它会按照模式开始打印内容,也可以将其直接传输到 bzip2/gzip,就像在 Debian 上perl chop.pl input_sql.bz2 | bzip2 > out.sql.bz2 需要的那样。libio-compress-perl

相关内容