巨大なファイルの先頭からテキストを削除する最良の方法

巨大なファイルの先頭からテキストを削除する最良の方法

アルファベット順に並べられたテーブルを含む巨大な 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 を 2 回実行し、すべてのバイトを 2 回読み取る必要があります。

これを一度にすべて実行する方法はありますか?

私の 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

「これは私の質問への答えになっていない」と言うのは、まだファイルを調べるのに 2 回必要だからです。1 回は探しているもののオフセットを見つけるため、もう 1 回はファイルをトリミングするためです。

カスタムプログラムに戻れば、ケムピープログラムの「読み取り専用」フェーズ中に実行し、その後「すべてを読み取り+書き込み」に切り替えます。

答え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;
}

つまり、基本的にはパターンの後に内容を印刷し始めますが、 Debian でperl chop.pl input_sql.bz2 | bzip2 > out.sql.bz2 必要なように、それを bzip2/gzip に直接パイプすることもできますlibio-compress-perl

関連情報