Лучший способ удалить текст из начала большого файла

Лучший способ удалить текст из начала большого файла

У меня есть огромный файл резервной копии 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.

Связанный контент