Puncte:5

Cel mai bun mod de a elimina textul de la începutul unui fișier uriaș

drapel de

Am un fișier de rezervă uriaș MySQL (de la mysqldump) cu tabelele în ordine alfabetică. Restaurarea mea a eșuat și vreau să reiau de unde am rămas cu următorul tabel din fișierul de rezervă. (Am corectat problema, aceasta nu este chiar o întrebare despre restaurările MySQL etc.)

Ceea ce aș dori să fac este să îmi iau fișierul de rezervă, de ex. backup.sql și decupează începutul fișierului până când văd această linie:

-- Structura tabelului pentru `mytable`

Apoi, totul după aceea va ajunge în fișierul meu rezultat, să zicem backup-secondhalf.sql. Acest lucru este oarecum complicat de faptul că fișierul este comprimat bzip2, dar asta nu ar trebui să fie o afacere prea mare.

Cred ca pot sa fac asa:

$ bunzip2 -c backup.sql.bz2 | grep --text --byte-offset --only-matching -e '--Structura tabelului pentru tabelul `mytable`' -m 1

Acest lucru îmi va oferi offset-ul de octeți din fișierul pe care vreau să-l decup pâna la. Atunci:

$ bunzip2 -c backup.sql.bz2 | dd skip=[numărul de sus] | bzip2 -c > backup-secondhalf.sql.bz2

Din păcate, acest lucru necesită să rulez bunzip2 pe fișier de două ori și să citesc toți acești octeți de două ori.

Există vreo modalitate de a face asta dintr-o dată?

Nu sunt sigur că sed-fu-ul meu este suficient de puternic pentru a face o expresie „șterge toate liniile până la expresia obișnuită, apoi lăsați restul fișierului să treacă”.

Acesta este pe Debian Linux, așa că am instrumente GNU disponibile.

drapel eg
Dacă liniile pot avea o lungime arbitrar lungă, de unde știi că grep va putea localiza șirul țintă `--Table structure`? De asemenea, șirul țintă este întotdeauna la începutul unei linii? Dacă da, atunci un program personalizat ar trebui să funcționeze chiar și pentru linii arbitrar lungi (N = lungimea șirului țintă fix): citiți un buffer, localizați fiecare linie nouă pe rând, verificați dacă există N caractere în tampon după linia nouă (altfel mutați linia nouă la începutul lui buffer, umple restul de buffer), verificați șirul țintă după linia nouă, treceți la următoarea linie nouă dacă nu este găsită. Nu este nevoie de KMP.
drapel eg
Dacă datele au fost deja necomprimate într-un fișier obișnuit (care poate fi căutat), atunci `grep -m1` urmat de `cat` ar funcționa.
Puncte:8
drapel vn
bunzip2 -c backup.sql.bz2 | \
  sed -n '/-- Structura tabelului pentru `mytable`/,$p'

Explicaţie:

-n suprima imprimarea automată a spațiului de model

Construcția intervalului de adrese: Începeți cu regex

/-- Structura tabelului pentru `mytable`/

Se termina cu

$ Potriviți ultima linie.

Comanda

p Tipăriți spațiul curent al modelului.

Editare: în funcție de modul în care ați descărcat baza de date pe care o aveți foarte linii lungi. GNU sed le poate gestiona până la cantitatea de memorie disponibilă.

drapel de
Într-adevăr, am rânduri foarte lungi. Acesta este un sistem de 64 de biți, așa că teoretic ar putea fi dispus să aloce până la 2^64 de octeți unui singur proces. Dar memoria mea fizică este limitată la 64 GiB, iar schimbul nu se apropie de intervalul de gigabyte. Așa că cred că întreg spațiul modelului nu s-ar încadra în memorie pentru acele linii lungi.
Puncte:2
drapel de

NOTĂ: Nu este un răspuns real

Din moment ce am fost motivat să rezolv asta acum, am mers înainte și am folosit grep să găsesc offset-ul în fișierul pe care l-am dorit; a funcționat grozav.

Alergare dd din păcate necesită să setați ibs=1 ceea ce înseamnă practic lipsă de tamponare, iar performanța este groaznică. În timp ce așteptam finalizarea dd, mi-am petrecut timp scriind propriul program C personalizat pentru a sări peste octeți. După ce am făcut asta, văd asta coadă ar fi putut face asta pentru mine la fel de ușor:

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

Spun „asta nu răspunde la întrebarea mea” pentru că mai necesită două treceri prin fișier: una pentru a găsi offset-ul lucrului pe care îl caut și alta pentru a tăia fișierul.

Dacă ar fi să mă întorc la programul meu personalizat, aș putea implementa un KMP în timpul fazei „numai citire” a programului și apoi trecerea la „citește+scrie totul” după aceea.

Puncte:0
drapel cn

Mă întreb dacă ceva de genul ăsta ar face smecheria:

folosiți strict;
folosiți avertismente;
utilizați caracteristica „spune”;

utilizați IO::Uncompress::Bunzip2 '$Bunzip2Error';

my $file = $ARGV[0] // mor „am nevoie de un fișier”;

my $zh = IO::Uncompress::Bunzip2->new( $fișier, {
    Închidere automată => 1,
    Transparent => 1,
} ) sau die "IO::Uncompress::Bunzip2 failed: $Bunzip2Error\n";

my $trigger = undef;
în timp ce ( <$zh> ) {
    chomp;
    $trigger = 1 if $_ eq '-- Dumping date pentru tabelul `experimente`';
    spune dacă $trigger;
}

Deci, practic, începe să imprime lucruri după model, se poate, de asemenea, să le direcționeze direct către bzip2/gzip, cum ar fi perl chop.pl input_sql.bz2 | bzip2 > out.sql.bz2 Ai avea nevoie libio-compress-perl pe Debian.

drapel de
Acest lucru poate funcționa, dar poate fie să nu funcționeze, fie să rămână fără memorie, în funcție de modul în care Perl tratează liniile lungi. Cred că `` va sfârși prin a citi un rând în întregime în memorie și probabil că asta va exploda. Unele dintre aceste linii sunt lungi de zeci de GiB.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.