Verwenden von "Kopf" oder "Schwanz" in einer riesigen Textdatei - 19 GB

14

Ich habe ein Problem beim Anzeigen von Teilen einer sehr großen Textdatei. Diese Datei, ungefähr 19 GB, ist offensichtlich zu groß, um mit herkömmlichen Mitteln angezeigt zu werden.

Ich habe versucht head 1und tail 1( head -n 1und tail -n 1) mit beiden Befehlen auf verschiedene Art und Weise (um zu einem Stück in der Mitte zu kommen) ohne Glück zusammengeschickt. Mein Linux-Rechner mit Ubuntu 9.10 kann diese Datei nicht verarbeiten.

Wie gehe ich mit dieser Datei um? Mein ultimatives Ziel ist es, die Linien 45000000 und 45000100 zu verbessern.

nicorellius
quelle
Ich denke darüber nach, ein schnelles Python-Skript zu schreiben, um die Zeilen zu lesen und die auszudrucken, die ich
archivieren
Sind alle Zeilen gleich lang?
Paul
@Paul - leider sind sie nicht gleich lang.
Nicorellius
Sie können versuchen split, die Arbeit mit der großen Datei zu vereinfachen.
Iglvzx
1
In Ordnung. Die Bearbeitung einer so großen Datei wird einige Zeit in Anspruch nehmen. Die folgenden Antworten helfen Ihnen dabei. Wenn Sie nur das Teil extrahieren möchten, nach dem Sie suchen, und ungefähr schätzen können, wo es sich befindet, können Sie es verwenden dd, um das gewünschte Teil zu erhalten. Zum Beispiel dd if=bigfile of=extractfile bs=1M skip=10240 count=5werden 5 MB aus der Datei ab dem 10-GB-Punkt extrahiert.
Paul

Antworten:

11

Sie sollten verwenden sed.

sed -n -e 45000000,45000100p -e 45000101q bigfile > savedlines

Dies weist sedan, die Zeilen 45000000-45000100 einschließlich zu drucken und in Zeile 45000101 zu beenden.

Kyle Jones
quelle
1
Es ist immer noch sehr langsam, fast wie head -45000000,45000100p bigfile | tail -100> savedlines
Dmitry Polushkin
tail+|headist um gut 10-15% schneller.
Erich
4

Erstellen Sie eine MySQL-Datenbank mit einer einzelnen Tabelle, die ein einzelnes Feld enthält. Importieren Sie dann Ihre Datei in die Datenbank. Dies macht es sehr einfach, eine bestimmte Zeile nachzuschlagen.

Ich glaube nicht, dass etwas anderes schneller sein könnte (wenn headund tailschon scheitern). Am Ende muss die Anwendung, die eine Zeile finden möchte, ndie gesamte Datei ndurchsuchen, bis neue Zeilen gefunden wurden. Ohne eine Suche (Zeilenindex zu Byte-Versatz in der Datei) kann keine bessere Leistung erzielt werden.

Angesichts der Tatsache, wie einfach es ist, eine MySQL-Datenbank zu erstellen und Daten in diese zu importieren, halte ich dies für einen praktikablen Ansatz.

So geht's:

DROP DATABASE IF EXISTS helperDb;
CREATE DATABASE `helperDb`;
CREATE TABLE `helperDb`.`helperTable`( `lineIndex` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `lineContent` MEDIUMTEXT , PRIMARY KEY (`lineIndex`) );
LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable (lineContent);
SELECT lineContent FROM helperTable WHERE ( lineIndex > 45000000 AND lineIndex < 45000100 );

/tmp/my_large_file wäre die Datei, die Sie lesen möchten.

Die korrekte Syntax zum Importieren einer Datei mit durch Tabulatoren getrennten Werten in jeder Zeile lautet:

LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable FIELDS TERMINATED BY '\n' (lineContent);

Ein weiterer großer Vorteil ist, dass Sie, wenn Sie später weitere Zeilen extrahieren möchten, nicht noch einmal stundenlang auf die Verarbeitung warten müssen (es sei denn, Sie löschen natürlich die Datenbank).

Der Hochstapler
quelle
Das ist in der Tat eine gute Lösung. Ich ließ es mit dem folgenden sedBefehl arbeiten und identifizierte meine Zeilen. Jetzt habe ich jedoch eine weitere Frage, für die die Datenbankmethode möglicherweise besser geeignet ist. Ich muss jetzt ein paar hundert Zeilen aus der Datei löschen.
Nicorellius
Das könnte ich sicher sedauch. Wenn Sie die Daten in der Datenbank hätten, wäre es natürlich trivial, eine neue Datei mit nur den gewünschten Zeilen zu exportieren.
Der Hochstapler
Danke noch einmal. Ich habe die sedAntwort angenommen (weil es mir sofort mehr Freude bereitet hat ;-)), habe Sie aber positiv bewertet, weil ich Ihre Methode in Zukunft anwenden werde. Ich schätze es.
Nicorellius
1
Sie können versuchen, ein FIELDS TERMINATED BY '\n'in die LOAD DATAZeile einzufügen.
Der Hochstapler
1
Es tut mir leid, es gab einen Fehler in meinem Code. Ich habe auch die richtige Syntax für Ihren Fall hinzugefügt (diesmal getestet).
Der Hochstapler
1

Zwei gute alte Tools für große Dateien sind joinund split. Sie können die --lines=<number>Option " Teilen mit " verwenden, um Dateien in mehrere Dateien einer bestimmten Größe zu schneiden.

Zum Beispiel split --lines=45000000 huge_file.txt. Die resultierenden Teile wären in xa, xb usw. Dann können Sie headden Teil xb , der die gewünschten Zeilen enthalten würde. Sie können Dateien auch wieder zu einer großen Datei zusammenfügen.

Anssi
quelle
Super, danke, ich habe den Split-Befehl total vergessen.
Siliconrockstar
0

Sie haben die richtigen Werkzeuge, verwenden sie aber falsch. Wie bereits bei U & L beantwortet , ist tail -n +X file | head -n Y(beachte das +) 10-15% schneller als sedbei Y-Linien, die bei X beginnen. Und bequemerweise müssen Sie exitden Vorgang nicht explizit wie bei ausführen sed.

tail liest und verwirft die ersten X-1-Zeilen (daran führt kein Weg vorbei), liest und druckt dann die folgenden Zeilen. head liest und druckt die angeforderte Anzahl von Zeilen und beendet dann. Beim Verlassen des Heads empfängt der Tail ein SIGPIPE-Signal und stirbt, sodass er nicht mehr als eine Puffergröße (normalerweise ein paar Kilobyte) Zeilen aus der Eingabedatei gelesen hat.

Erich
quelle