Ich glaube nicht, dass Sie das können - nicht zuverlässig und nicht so, wie Sie es verlangen. Die Sache ist, dass das Komprimierungsverhältnis des Archivs wahrscheinlich nicht gleichmäßig von Kopf bis Schwanz verteilt sein wird - der Komprimierungsalgorithmus wird auf einige Teile besser angewendet als auf andere. So funktioniert es einfach. Daher können Sie Ihren Split nicht anhand der Größe der komprimierten Datei berücksichtigen.
Was mehr ist , gzip
unterstützt nicht nur die Originalgröße von komprimierten Dateien zu speichern mehr als 4gbs Größe - es kann nicht damit umgehen. Sie können das Archiv also nicht abfragen, um eine zuverlässige Größe zu erhalten - weil es Sie täuschen wird.
Die 4-Zeilen-Sache - das ist wirklich ziemlich einfach. Die 4-Datei-Sache - ich weiß nur nicht, wie Sie es zuverlässig und mit einer gleichmäßigen Verteilung machen können, ohne zuerst das Archiv zu extrahieren, um seine unkomprimierte Größe zu erhalten. Ich glaube nicht, dass du es kannst, weil ich es versucht habe.
Sie können jedoch eine maximale Größe für geteilte Ausgabedateien festlegen und sicherstellen, dass diese immer an Rekordbarrieren beschädigt werden. Das kannst du leicht machen. Hier ist ein kleines Skript, das dies tut, indem es das gzip
Archiv extrahiert und den Inhalt durch einige explizite dd
Pipe-Puffer mit bestimmten count=$rpt
Argumenten leitet , bevor es weitergeleitet wird, lz4
um jede Datei im laufenden Betrieb zu dekomprimieren / erneut zu komprimieren. Ich habe auch ein paar kleine tee
Pipe-Tricks reingeworfen, um die letzten vier Zeilen für jedes Segment auch an stderr zu drucken.
( IFS= n= c=$(((m=(k=1024)*k)/354))
b=bs=354xk bs=bs=64k
pigz -d </tmp/gz | dd i$bs o$b |
while read -r line _$((n+=1))
do printf \\n/tmp/lz4.$n\\n
{ { printf %s\\n "$line"
dd count=$c i$b o$bs
}| tee /dev/fd/3|lz4 -BD -9 >/tmp/lz4.$n
} 3>&1| tail -n4 |tee /dev/fd/2 |
wc -c;ls -lh /tmp/[gl]z*
done
)
Das geht einfach so lange weiter, bis alle Eingaben verarbeitet wurden. Es wird nicht versucht, es um einen bestimmten Prozentsatz zu teilen - den es nicht erhalten kann -, sondern es wird nach einer maximalen Anzahl von Rohbytes pro Teilung aufgeteilt. Ein großer Teil Ihres Problems besteht darin, dass Sie keine zuverlässige Größe für Ihr Archiv erhalten können, weil es zu groß ist - was auch immer Sie tun, tun Sie das nicht noch einmal - machen Sie die Splits weniger als 4 GB pro Stück , vielleicht. Zumindest mit diesem kleinen Skript können Sie dies tun, ohne jemals ein unkomprimiertes Byte auf die Festplatte schreiben zu müssen.
Hier ist eine kürzere Version, die auf das Wesentliche reduziert ist - sie fügt nicht alle Berichte hinzu:
( IFS= n= c=$((1024*1024/354))
pigz -d | dd ibs=64k obs=354xk |
while read -r line _$((n+=1))
do { printf %s\\n "$line"
dd count=$c obs=64k ibs=354xk
} | lz4 -BD -9 >/tmp/lz4.$n
done
) </tmp/gz
Es macht alle die gleichen Dinge wie das erste, meistens hat es einfach nicht so viel zu sagen. Außerdem gibt es weniger Unordnung, sodass Sie vielleicht leichter sehen können, was los ist.
Die IFS=
Sache ist nur, die eine read
Zeile pro Iteration zu behandeln. Wir read
eins, weil wir unsere Schleife brauchen, um zu enden, wenn die Eingabe endet. Dies hängt von Ihrem rekord Größe -, die pro Ihr Beispiel ist 354 Bytes pro. Ich habe ein 4 + GB- gzip
Archiv mit einigen zufälligen Daten erstellt, um es zu testen.
Die zufälligen Daten wurden folgendermaßen erhalten:
( mkfifo /tmp/q; q="$(echo '[1+dPd126!<c]sc33lcx'|dc)"
(tr '\0-\33\177-\377' "$q$q"|fold -b144 >/tmp/q)&
tr '\0-\377' '[A*60][C*60][G*60][N*16][T*]' | fold -b144 |
sed 'h;s/^\(.\{50\}\)\(.\{8\}\)/@N\1+\2\n/;P;s/.*/+/;H;x'|
paste "-d\n" - - - /tmp/q| dd bs=4k count=kx2k | gzip
) </dev/urandom >/tmp/gz 2>/dev/null
... aber vielleicht müssen Sie sich darüber nicht so viele Sorgen machen, da Sie bereits über die Daten und alles verfügen. Zurück zur Lösung ...
Grundsätzlich pigz
- was etwas schneller zu dekomprimieren scheint zcat
- leitet der unkomprimierte Stream und die dd
Puffer, die in Schreibblöcke ausgegeben werden, die speziell mit einem Vielfachen von 354 Bytes dimensioniert sind, weiter. Die Schleife wird read
ein $line
einmal jede Iteration zu testen , die Eingabe noch ankommen, was es wird printf
danach printf
an , lz4
bevor ein andere dd
genannten Blöcke zu lesen , mit einem Mehrfachen bemessen speziell von 354 Bytes - zum Synchronisieren mit dem Pufferprozessdd
- für die Dauer. Aufgrund der Initiale wird es einen kurzen Lesevorgang pro Iteration geben read $line
- aber das spielt keine Rolle, da wir diesen lz4
ohnehin bei - unserem Collector-Prozess - drucken .
Ich habe es so eingerichtet, dass jede Iteration ungefähr 1 GB unkomprimierte Daten liest und diesen In-Stream auf ungefähr 650 MB oder so komprimiert. lz4
ist weitaus schneller als so ziemlich jede andere nützliche Komprimierungsmethode - weshalb ich sie hier gewählt habe, weil ich nicht gerne warte. xz
würde wahrscheinlich beim eigentlichen Komprimieren einen viel besseren Job machen. Eine Sache lz4
ist jedoch, dass es häufig mit einer RAM-Geschwindigkeit dekomprimiert werden kann - was bedeutet, dass Sie ein lz4
Archiv häufig nur schnell dekomprimieren können, da Sie es ohnehin in den Speicher schreiben könnten.
Der Große macht ein paar Berichte pro Iteration. Beide Schleifen drucken dd
den Bericht über die Anzahl der übertragenen Rohbytes und die Geschwindigkeit und so weiter. Die große Schleife druckt auch die letzten 4 Eingabezeilen pro Zyklus und eine Byteanzahl für dieselbe, gefolgt von einem ls
der Verzeichnisse, in die ich die lz4
Archive schreibe . Hier sind einige Ausgaberunden:
/tmp/lz4.1
2961+1 records in
16383+1 records out
1073713090 bytes (1.1 GB) copied, 169.838 s, 6.3 MB/s
@NTACGTANTTCATTGGNATGACGCGCGTTTATGNGAGGGCGTCCGGAANGC+TCTCTNCC
TACGTANTTCATTGGNATGACGCGCGTTTATGNGAGGGCGTCCGGAANGCTCTCTNCCGAGCTCAGTATGTTNNAAGTCCTGANGNGTNGCGCCTACCCGACCACAACCTCTACTCGGTTCCGCATGCATGCAACACATCGTCA
+
I`AgZgW*,`Gw=KKOU:W5dE1m=-"9W@[AG8;<P7P6,qxE!7P4##,Q@c7<nLmK_u+IL4Kz.Rl*+w^A5xHK?m_JBBhqaLK_,o;p,;QeEjb|">Spg`MO6M'wod?z9m.yLgj4kvR~+0:.X#(Bf
354
-rw-r--r-- 1 mikeserv mikeserv 4.7G Jun 16 08:58 /tmp/gz
-rw-r--r-- 1 mikeserv mikeserv 652M Jun 16 12:32 /tmp/lz4.1
/tmp/lz4.2
2961+1 records in
16383+1 records out
1073713090 bytes (1.1 GB) copied, 169.38 s, 6.3 MB/s
@NTTGTTGCCCTAACCANTCCTTGGGAACGCAATGGTGTGANCTGCCGGGAC+CTTTTGCT
TTGTTGCCCTAACCANTCCTTGGGAACGCAATGGTGTGANCTGCCGGGACCTTTTGCTGCCCTGGTACTTTTGTCTGACTGGGGGTGCCACTTGCAGNAGTAAAAGCNAGCTGGTTCAACNAATAAGGACNANTTNCACTGAAC
+
>G-{N~Q5Z5QwV??I^~?rT+S0$7Pw2y9MV^BBTBK%HK87(fz)HU/0^%JGk<<1--7+r3e%X6{c#w@aA6Q^DrdVI0^8+m92vc>RKgnUnMDcU:j!x6u^g<Go?p(HKG@$4"T8BWZ<z.Xi
354
-rw-r--r-- 1 mikeserv mikeserv 4.7G Jun 16 08:58 /tmp/gz
-rw-r--r-- 1 mikeserv mikeserv 652M Jun 16 12:32 /tmp/lz4.1
-rw-r--r-- 1 mikeserv mikeserv 652M Jun 16 12:35 /tmp/lz4.2
zcat file > /dev/null
?