Eu não acho que você possa fazer isso - não de maneira confiável e não do jeito que você pergunta. O problema é que a taxa de compactação do arquivo provavelmente não será distribuída igualmente da cabeça à cauda - o algoritmo de compactação se aplicará melhor a algumas partes do que a outras. É assim que funciona. E, portanto, você não pode fatorar sua divisão no tamanho do arquivo compactado.
Além disso, gzip
simplesmente não suporta armazenar o tamanho original de arquivos compactados com mais de 4 gbs de tamanho - ele não pode lidar com isso. Portanto, você não pode consultar o arquivo para obter um tamanho confiável - porque isso o enganará.
A coisa de 4 linhas - é bem fácil, na verdade. A coisa dos 4 arquivos - simplesmente não sei como você poderia fazer isso de maneira confiável e com uma distribuição uniforme, sem primeiro extrair o arquivo para obter seu tamanho descompactado. Eu não acho que você pode, porque eu tentei.
No entanto, o que você pode fazer é definir um tamanho máximo para arquivos de saída divididos e garantir que eles sempre sejam quebrados em barreiras de registro. Isso você pode fazer facilmente. Aqui está um pequeno script que fará isso extraindo o gzip
arquivo morto e canalizando o conteúdo através de alguns dd
buffers de pipe explícitos com count=$rpt
argumentos específicos , antes de repassá-lo lz4
para descomprimir / recomprimir cada arquivo em tempo real. Também fiz alguns tee
truques para imprimir as últimas quatro linhas de cada segmento para stderr também.
( 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
)
Isso continuará até que ele lide com todas as entradas. Ele não tenta dividi-lo por alguma porcentagem - o que não pode ser obtido -, mas o divide por uma contagem máxima de bytes brutos por divisão. De qualquer forma, grande parte do seu problema é que você não pode obter um tamanho confiável em seu arquivo porque é muito grande - faça o que fizer, não faça isso de novo - faça com que as divisões sejam inferiores a 4 gbs por peça. , talvez. Este pequeno script, pelo menos, permite que você faça isso sem precisar gravar um byte descompactado no disco.
Aqui está uma versão mais curta, simplificada - ela não adiciona todo o material do relatório:
( 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
Ele faz as mesmas coisas que o primeiro, principalmente, mas não tem muito a dizer sobre isso. Além disso, há menos confusão, por isso é mais fácil ver o que está acontecendo, talvez.
A IFS=
questão é apenas lidar com uma read
linha por iteração. Nós read
um porque precisamos que nosso loop termine quando a entrada terminar. Isso depende do tamanho do seu registro - que, por exemplo, é de 354 bytes por. Criei um gzip
arquivo de 4 + gb com alguns dados aleatórios para testá-lo.
Os dados aleatórios foram obtidos desta maneira:
( 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
... mas talvez você não precise se preocupar muito com isso, já que você já tem os dados e tudo. Voltar para a solução ...
Basicamente pigz
- o que parece descomprimir um pouco mais rápido do que o faz zcat
- canaliza o fluxo não compactado e os dd
buffers que saem em blocos de gravação dimensionados especificamente para um múltiplo de 354 bytes. O loop será repetido read
uma $line
vez a cada iteração para testar se a entrada ainda está chegando, que será printf
posteriormenteprintf
no lz4
antes de um outro dd
é chamada para ler blocos dimensionado especificamente a um múltiplo de 354 bytes - sincronizar com o tamponamento dd
processo - para a duração. Haverá uma leitura curta por iteração por causa da inicial read $line
- mas isso não importa, porque estamos imprimindo isso no lz4
- nosso processo de coletor - de qualquer maneira.
Eu o configurei para que cada iteração leia aproximadamente 1 gb de dados não compactados e comprima esse in-stream para cerca de 650 Mb ou mais. lz4
é muito mais rápido do que qualquer outro método de compactação útil - e foi por isso que o escolhi aqui porque não gosto de esperar. xz
provavelmente faria um trabalho muito melhor na compressão real. Uma coisa é lz4
, porém, que muitas vezes é possível descompactar a velocidades próximas à RAM - o que significa que muitas vezes você pode descomprimir um lz4
arquivo tão rápido quanto seria possível gravá-lo na memória.
O grande faz alguns relatórios por iteração. Os dois loops imprimirão dd
o relatório sobre o número de bytes brutos transferidos, a velocidade e assim por diante. O loop grande também imprimirá as últimas 4 linhas de entrada por ciclo, e uma contagem de bytes para o mesmo, seguida por um ls
diretório no qual escrevo os lz4
arquivos. Aqui estão algumas rodadas de saída:
/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
?