Ersetzen Sie Text schnell in sehr großen Dateien

24

Ich habe 25 GB Textdatei, die eine Zeichenfolge in nur wenigen Zeilen ersetzt werden muss. Ich kann sederfolgreich verwenden, aber das Ausführen dauert sehr lange.

sed -i 's|old text|new text|g' gigantic_file.sql

Gibt es einen schnelleren Weg, dies zu tun?

Eisaacson
quelle
Kennen Sie die Zeilennummern, in denen sich der zu ersetzende Text befindet? Wenn nicht Ihre einzige Möglichkeit zur Beschleunigung besteht darin, einen schnelleren Computer zu erhalten. Die Tatsache, dass Sie über eine große Datenmenge verfügen, bedeutet, dass das Durchsuchen dieser Daten viel Zeit in Anspruch nimmt.
David King
Ich kann ziemlich schnell nach den Zeilennummern suchen, also ja.
Eisaacson
Sie können auch mehrere CPU-Kerne zur Beschleunigung verwenden - rankfocus.com/use-cpu-cores-linux-commands
ahaswer
Verwenden Sie sed nicht für große Dateien. Schauen Sie sich stattdessen vi oder vim an.
MikeJRamsey56

Antworten:

25

Du kannst es versuchen:

sed -i '/old text/ s//new text/g' gigantic_file.sql

Von diesem Verweis :

OPTIMIERUNG FÜR GESCHWINDIGKEIT: Wenn die Ausführungsgeschwindigkeit erhöht werden muss (aufgrund großer Eingabedateien oder langsamer Prozessoren oder Festplatten), wird die Ersetzung schneller ausgeführt, wenn der Ausdruck "find" angegeben wird, bevor "s /.../" eingegeben wird. ../" Anweisung.

Hier ist ein Vergleich über eine 10G-Datei. Vor:

$ time sed -i 's/original/ketan/g' wiki10gb
real    5m14.823s
user    1m42.732s
sys     1m51.123s

Nach:

$ time sed -i '/ketan/ s//original/g' wiki10gb
real    4m33.141s
user    1m20.940s
sys     1m44.451s
mkc
quelle
Der letzte sedist falsch geschrieben. Ich habe diesen Beitrag gestern bearbeitet, um den letzten sedBefehl zu korrigieren, der sein sollte time sed -i '/original/ s//ketan/g' wiki10gbund nicht time sed -i '/ketan/ s//original/g' wiki10gb. Ich mache meine Bearbeitung heute wieder rückgängig, weil 1. die Zeiten nicht mehr mit dem Befehl übereinstimmen und 2. ich denselben Test mit GNU an einer Datei mit mehr als 3 GB durchgeführt habe und keinen Unterschied zwischen den beiden sedAlternativen feststelle. Ich vermute, dass der Zeitunterschied auf die Rechtschreibfehler zurückzuführen ist.
Xhienne
@ xhienne Ich bin nicht sicher, was du mit Rechtschreibfehlern meinst. Im ersten Durchgang ersetze ich das Wort "Original" durch "Ketan" und im zweiten Durchgang ersetze ich den Begriff "Ketan" durch den Begriff "Original", was in beiden Fällen zu einer gleichen Anzahl von Substitutionen führt.
mkc
1
Ich habe ein "Update" angewendet, das von einem neuen Benutzer gemeldet wurde, der nicht über eine ausreichende Reputation verfügt. Jetzt verstehe ich, was du getan hast. Wenn Sie jedoch nachweisen möchten, dass eine Syntax besser ist als die andere, müssen Sie genau die gleiche Operation ausführen, die hier nicht der Fall ist (CPU-bezogen ist die Suche nach einem 5-Zeichen-String nicht die Suche nach einem 7-Zeichen-Zeichenfolge). Darüber hinaus hängt diese Art von Test für eine 10-GB-Datei stark von Ihrer Maschinenlast (CPU, Festplatte) ab. Ich timepersönlich habe viele Schwankungen in den Ergebnissen gesehen, aber insgesamt gab es keinen Zeitunterschied.
Xhienne
Ich glaube, das hängt zusammen - siehe die akzeptierte Antwort hier, stackoverflow.com/questions/11145270/… >> sed streamt die gesamte Datei, aber wie in dieser Antwort angegeben, hilft die Angabe der Zeilennummer (falls bekannt): in meinem Fall , eine ~ 2-fache Steigerung der Ausführungsgeschwindigkeit (GNU sed 4.5). Sie können grep -n oder ripgrep (rg) verwenden, um Zeilennummern basierend auf Mustersuchen zu finden. In der Tat entspricht die Angabe der Zeilennummer der Angabe eines Suchergebnisses in dieser Datei gemäß der obigen Antwort.
Victoria Stuart
1

Die kurze Antwort lautet "Nein" - Ihr limitierender Faktor für diese Art von Operation ist Disk IO. Es gibt keine Möglichkeit, 25 GB einer Festplatte schneller zu streamen. Wenn Sie keine direkte Bearbeitung vornehmen und das Ergebnis sedauf ein separates Laufwerk schreiben (sofern vorhanden), können Sie möglicherweise eine geringfügige Verbesserung erzielen. Auf diese Weise können Sie von einem Laufwerk lesen, während Sie auf ein anderes schreiben weniger Streit als Ergebnis.

Sie könnte es beschleunigen sie ein wenig in der Lage durch nicht für jede Zeile der Regex - Engine - so zum Beispiel unter Verwendung von Perl (ich bin mir ziemlich sicher , dass Sie mit diesem tun , sedaber ich weiß nicht , die Syntax) - dies beginnt ab Zeile 10.000 weiter.

perl -pe '$. > 10_000 && s/old_text/new_text/g' 

Und wenn es irgendwelche Komplikationen in der RE (Metazeichen) gibt, wird die Effizienz der Regex-Engine leicht verbessert, wenn diese minimiert werden .

Sobrique
quelle
1
In Sed wäre dassed -i '10000,$ s/old_text/new_text/g'
Dani_l
Schön. Ich weiß nicht, wie man es sedvergleicht - ich nehme an, dass es ein bisschen schneller ist, aber aufgrund der Dateigröße nicht viel.
Sobrique
Ich nehme an, Perl ist schneller als sed, aber sed ist etwas weniger kryptisch oder erfordert weniger Einarbeitungszeit.
Dani_l
1
Siehe, jetzt würde ich das Gegenteil gesagt haben - können Sie (fast) schreiben sedin perl, aber diese können Sie auch ausführlichere Skripte zu schreiben.
Sobrique
0

Wenn der neue und der alte Text gleich lang sind, können Sie in die Datei suchen und nur die geänderten Bytes schreiben, anstatt die gesamte Datei zu kopieren. Andernfalls sind Sie in der Lage, viele Daten zu verschieben.

Hinweis: Dies ist schwierig und erfordert das Schreiben von benutzerdefiniertem Code.

Auf der Manpage finden Sie fseek, wenn Sie in C oder C ++ arbeiten, oder Ihre bevorzugten Sprach-Wrapper für das Suchen und Schreiben von Systemaufrufen.

Wenn Sie nur auf der Befehlszeile bestehen und die Byte-Offsets des Texts erhalten, können Sie den Ersetzungstext mit sorgfältig geschriebenen "dd" -Befehlen an die richtige Stelle schreiben.

gestohlener Moment
quelle