web-dev-qa-db-fra.com

Meilleure façon de supprimer le texte du début d'un énorme fichier

J'ai un énorme fichier de sauvegarde MySQL (de MySqldump) avec les tables de l'ordre alphabétique. Ma restauration a échoué et je veux ramasser là où je suis parti avec la table suivante dans le fichier de sauvegarde. (J'ai corrigé le problème, ce n'est pas vraiment une question sur les restaurations MySQL, etc.)

Ce que je voudrais faire, c'est prendre mon fichier de sauvegarde, par exemple backup.sql et couper le début du fichier jusqu'à ce que je vois cette ligne:

-- Table structure for `mytable`

Ensuite, tout après cela se retrouvera dans mon fichier de résultat, disons backup-secondhalf.sql. Ceci est quelque peu compliqué par le fait que le fichier est compressé de BZIP2, mais cela ne devrait pas être trop important d'une affaire.

Je pense que je peux le faire comme ça:

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

Cela me donnera le décalage des octets dans le fichier que je veux couper jusqu'à. Puis:

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

Malheureusement, cela vous oblige à exécuter Bunzip2 sur le fichier deux fois et à lire tous ces octets deux fois.

Y a-t-il un moyen de faire tout cela à la fois?

Je ne suis pas sûr que mon SED-FU soit suffisamment fort pour faire une "Supprimer toutes les lignes jusqu'à l'expression régulière, puis laisser le reste du fichier à travers" l'expression.

Ceci est sur Debian Linux, donc j'ai GNU Outils disponibles.

5

Remarque: non une réponse réelle

Depuis que j'ai été motivé pour obtenir ce résolu maintenant, je suis allé de l'avant et utilisé grep _ pour trouver le décalage dans le fichier que je voulais; Cela a fonctionné bien.

Exécution dd malheureusement exige que vous définisiez ibs=1 qui signifie fondamentalement aucun tampon et la performance est terrible. En attendant que DD complète, j'ai passé du temps à écrire mon propre programme C sur mesure pour sauter les octets. Après avoir fait cela, je vois que tail aurait pu le faire pour moi aussi facilement:

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

Je dis "cela ne répond pas à ma question" car il nécessite toujours deux passes dans le fichier: une pour trouver le décalage de la chose que je recherche et une autre pour couper le fichier.

Si je devais revenir à mon programme personnalisé, je pourrais implémenter un [~ # ~ # ~] KMP [~ # ~] lors de la phase "lecture seule" du programme, puis de passer à "Lire + écrire tout" après ça.

2

Je me demande si quelque chose comme ça ferait l'affaire:

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

Donc, fondamentalement, il commence à imprimer des trucs après le motif, on peut également le tuyer directement à bzip2/gzip, comme Perl chop.pl input_sql.bz2 | bzip2 > out.sql.bz2 Vous auriez besoin de libio-compress-Perl sur Debian.

0
mestia