Je ne pense pas que vous puissiez le faire - pas de manière fiable et pas de la façon dont vous le demandez. Le fait est que le taux de compression de l'archive ne sera probablement pas réparti uniformément de la tête à la queue - l'algorithme de compression s'appliquera mieux à certaines parties qu'à d'autres. Voilà comment ça fonctionne. Et vous ne pouvez donc pas prendre en compte votre division sur la taille du fichier compressé.
De plus, gzip
ne prend tout simplement pas en charge le stockage de la taille d'origine des fichiers compressés supérieurs à 4 Go - il ne peut pas le gérer. Et vous ne pouvez donc pas interroger l'archive pour obtenir une taille fiable, car cela vous trompera.
La chose à 4 lignes - c'est assez facile, vraiment. La chose à 4 fichiers - je ne sais tout simplement pas comment vous pouvez le faire de manière fiable et avec une distribution uniforme sans d'abord extraire l'archive pour obtenir sa taille non compressée. Je ne pense pas que vous puissiez le faire parce que j'ai essayé.
Cependant, ce que vous pouvez faire, c'est définir une taille maximale pour les fichiers de sortie divisés et assurez-vous qu'ils sont toujours cassés aux barrières d'enregistrement. Vous pouvez facilement le faire. Voici un petit script qui le fera en extrayant l' gzip
archive et en canalisant le contenu à travers quelques dd
tampons de canal explicites avec des count=$rpt
arguments spécifiques , avant de le passer lz4
pour décompresser / recompresser chaque fichier à la volée. J'ai également ajouté quelques tee
astuces pour imprimer les quatre dernières lignes de chaque segment sur stderr également.
( 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
)
Cela continuera simplement jusqu'à ce qu'il ait traité toutes les entrées. Il ne tente pas de le diviser par un certain pourcentage - ce qu'il ne peut pas obtenir - mais à la place, il le divise par un nombre maximal d'octets bruts par division. Et de toute façon, une grande partie de votre problème est que vous ne pouvez pas obtenir une taille fiable sur votre archive car elle est trop grande - quoi que vous fassiez, ne recommencez pas - faites des divisions de moins de 4 Go par morceau ce tour , peut être. Ce petit script, au moins, vous permet de le faire sans avoir à écrire un octet non compressé sur le disque.
Voici une version plus courte, dépouillée de l'essentiel - elle n'ajoute pas tous les éléments du rapport:
( 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
Il fait toutes les mêmes choses que le premier, surtout, il n'a tout simplement pas grand-chose à dire à ce sujet. De plus, il y a moins d'encombrement, il est donc plus facile de voir ce qui se passe, peut-être.
Le IFS=
problème est simplement de gérer une read
ligne par itération. Nous read
un parce que nous avons besoin que notre boucle se termine lorsque l'entrée se termine. Cela dépend de la taille de votre enregistrement - qui, selon votre exemple, est de 354 octets par. J'ai créé une gzip
archive 4 + gb avec des données aléatoires afin de la tester.
Les données aléatoires ont été obtenues de cette façon:
( 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
... mais peut-être que vous n'avez pas à vous en préoccuper autant, car vous avez déjà les données et tout. Retour à la solution ...
Fondamentalement pigz
- qui semble décompresser un peu plus vite que le fait zcat
- dirige le flux non compressé et les dd
tampons qui sortent en blocs d'écriture dimensionnés spécifiquement à un multiple de 354 octets. La boucle read
une $line
fois chaque itération de test d' entrée est encore arriver, qu'elle printf
ensuite printf
au lz4
devant un autre dd
est appelé pour lire des blocs de taille spécifiquement à un multiple de 354 octets - pour synchroniser avec le tampon dd
procédé - pour la durée. Il y aura une courte lecture par itération en raison de l'initiale read $line
- mais cela n'a pas d'importance, parce que nous l'imprimons dans lz4
- notre processus de collecte - de toute façon.
Je l'ai configuré de sorte que chaque itération lira environ 1 Go de données non compressées et les compressera en flux à environ 650 Mo environ. lz4
est beaucoup plus rapide que n'importe quelle autre méthode de compression utile - c'est la raison pour laquelle je l'ai choisie ici parce que je n'aime pas attendre. xz
ferait un bien meilleur travail à la compression réelle, probablement, cependant. Une chose lz4
, cependant, est qu'il peut souvent décompresser à des vitesses proches de la RAM - ce qui signifie que vous pouvez décompresser une lz4
archive très rapidement, car vous pourriez de toute façon l'écrire en mémoire.
Le grand fait quelques rapports par itération. Les deux boucles imprimeront dd
le rapport sur le nombre d'octets bruts transférés et la vitesse et ainsi de suite. La grande boucle affichera également les 4 dernières lignes d'entrée par cycle, et un nombre d'octets pour celui-ci, suivi d'un ls
répertoire dans lequel j'écris les lz4
archives. Voici quelques tours de sortie:
/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
?