
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.sql
e 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 grep
encontrei o deslocamento no arquivo que queria; funcionou muito bem.
Infelizmente, a execução dd
requer que você defina, ibs=1
o 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 tail
poderia 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-perl
no Debian.