Melhor maneira de remover texto do início de um arquivo enorme

Melhor maneira de remover texto do início de um arquivo enorme

Eu tenho um enorme arquivo de backup do MySQL (do mysqldump) com as tabelas em ordem alfabética. Minha restauração falhou e quero continuar de onde parei com a próxima tabela no arquivo de backup. (Eu corrigi o problema, esta não é realmente uma questão sobre restaurações do MySQL, etc.)

O que eu gostaria de fazer é pegar meu arquivo de backup, por exemplo, backup.sqle cortar o início do arquivo até ver esta linha:

-- Table structure for `mytable`

Então, tudo depois disso terminará no meu arquivo de resultados, digamos backup-secondhalf.sql. Isso é um pouco complicado pelo fato de o arquivo ser compactado em bzip2, mas isso não deve ser um grande problema.

Acho que posso fazer assim:

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

Isso me dará o deslocamento de bytes no arquivo que desejo cortaraté. Então:

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

Infelizmente, isso exige que eu execute bunzip2 no arquivo duas vezes e leia todos esses bytes duas vezes.

Existe uma maneira de fazer isso tudo de uma vez?

Não tenho certeza se meu sed-fu é forte o suficiente para fazer uma expressão "excluir todas as linhas até a expressão regular e depois deixar o resto do arquivo passar".

Isso está no Debian Linux, então tenho ferramentas GNU disponíveis.

Responder1

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

Explicação:

-n suppress automatic printing of pattern space

Construção de intervalo de endereços: comece com regex

/-- Table structure for  `mytable`/

Terminar com

$ Match the last line.

Comando

p Print the current pattern space.

Editar: dependendo de como você despejou o banco de dados, você pode termuitolongas filas. GNU sed pode lidar com eles até a quantidade de memória disponível.

Responder2

NOTA: Não é uma resposta real

Já que eu estava motivado para resolver issoagora, fui em frente e grepencontrei o deslocamento no arquivo que queria; funcionou muito bem.

Infelizmente, a execução ddrequer que você defina, ibs=1o que basicamente significa que não há buffer e o desempenho é terrível. Enquanto esperava a conclusão do dd, passei um tempo escrevendo meu próprio programa C personalizado para pular os bytes. Depois de fazer isso, vejo que tailpoderia ter feito isso por mim com a mesma facilidade:

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

Digo "isso não responde à minha pergunta" porque ainda requer duas passagens pelo arquivo: uma para encontrar o deslocamento do que estou procurando e outra para cortar o arquivo.

Se eu voltasse ao meu programa personalizado, poderia implementar umKMPdurante a fase "somente leitura" do programa e depois mude para "ler + escrever tudo" depois disso.

Responder3

Eu me pergunto se algo assim funcionaria:

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

Então, basicamente, ele começa a imprimir coisas após o padrão, também é possível canalizá-lo diretamente para bzip2/gzip, como perl chop.pl input_sql.bz2 | bzip2 > out.sql.bz2 você precisaria libio-compress-perlno Debian.

informação relacionada