Ich bin sicher, dass jemand das folgende Bedürfnis schon einmal hatte: Wie kann man eine riesige .gz-Datei schnell zeilenweise aufteilen? Die zugrunde liegende Textdatei hat 120 Millionen Zeilen. Ich habe nicht genug Speicherplatz, um die gesamte Datei auf einmal zu komprimieren, also habe ich mich gefragt, ob jemand ein Bash-/Perl-Skript oder -Tool kennt, mit dem man die Datei (entweder die .gz- oder die innere .txt-Datei) in 3 Dateien mit 40 Millionen Zeilen aufteilen kann. Das könnte man zum Beispiel so aufrufen:
bash splitter.sh hugefile.txt.gz 4000000 1
would get lines 1 to 40 mn
bash splitter.sh hugefile.txt.gz 4000000 2
would get lines 40mn to 80 mn
bash splitter.sh hugefile.txt.gz 4000000 3
would get lines 80mn to 120 mn
Ist es vielleicht eine Lösung, mehrere davon auszuführen, oder würde gunzip -c genug Speicherplatz benötigen, um die gesamte Datei zu entpacken (also das ursprüngliche Problem): gunzip -c hugefile.txt.gz | head 4000000
Hinweis: Ich kann keine zusätzliche Festplatte bekommen.
Danke!
Antwort1
Wie Sie dabei am besten vorgehen, hängt von Ihren Wünschen ab:
- Möchten Sie einen einzelnen Teil der großen Datei extrahieren?
- Oder möchten Sie alle Teile in einem Rutsch erstellen?
Wenn Sie eineeinzelner Teil der Datei, Ihre Idee zu verwenden gunzip
und head
ist richtig. Sie können verwenden:
gunzip -c hugefile.txt.gz | head -n 4000000
Dadurch würden die ersten 4.000.000 Zeilen über die Standardausgabe ausgegeben. Wahrscheinlich möchten Sie eine weitere Pipe anhängen, um tatsächlich etwas mit den Daten zu tun.
Um die anderen Teile zu erhalten, verwenden Sie eine Kombination aus head
und tail
, etwa:
gunzip -c hugefile.txt.gz | head -n 8000000 |tail -n 4000000
um den zweiten Block zu erhalten.
Ist es vielleicht eine Lösung, mehrere davon auszuführen, oder würde gunzip -c genug Speicherplatz benötigen, um die gesamte Datei zu entpacken?
Nein, dafür gunzip -c
ist kein Speicherplatz erforderlich. Der Vorgang wird im Speicher ausgeführt und anschließend auf die Standardausgabe gestreamt.
Wenn Sie erstellen möchtenalle Teile auf einmal, es ist effizienter, sie alle mit einem einzigen Befehl zu erstellen, da die Eingabedatei dann nur einmal gelesen wird. Eine gute Lösung ist die Verwendung von split
; Einzelheiten finden Sie in der Antwort von Jim McNamara.
Antwort2
Um die Pipe zu teilen, verwenden Sie entweder gunzip -c oder zcat, um die Datei zu öffnen
gunzip -c bigfile.gz | split -l 400000
Fügen Sie dem Split-Befehl Ausgabespezifikationen hinzu.
Antwort3
Da Sie an einem (nicht zurückspulbaren) Stream arbeiten, möchten Sie die „+N“-Form des Endes verwenden, um Zeilen ab Zeile N zu erhalten.
zcat hugefile.txt.gz | head -n 40000000
zcat hugefile.txt.gz | tail -n +40000001 | head -n 40000000
zcat hugefile.txt.gz | tail -n +80000001 | head -n 40000000
Antwort4
.gz-Datei direkt in .gz-Dateien aufteilen:
zcat bigfile.gz | split -l 400000 --filter='gzip > $FILE.gz'
Ich denke, das ist es, was OP wollte, weil er nicht viel Platz hat.