
У меня есть огромный файл резервной копии 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, как perl chop.pl input_sql.bz2 | bzip2 > out.sql.bz2
это может понадобиться libio-compress-perl
в Debian.