Nie sądzę, żebyś mógł to zrobić - niezawodnie i nie tak, jak prosisz. Chodzi o to, że współczynnik kompresji archiwum prawdopodobnie nie będzie równomiernie rozłożony od głowy do ogona - algorytm kompresji będzie miał zastosowanie w niektórych częściach lepiej niż w innych. Tak to działa. I dlatego nie możesz brać pod uwagę podziału na rozmiar skompresowanego pliku.
Co więcej, gzip
po prostu nie obsługuje przechowywania oryginalnego rozmiaru skompresowanych plików większych niż 4 GB - nie może tego obsłużyć. Nie możesz więc zapytać archiwum, aby uzyskać niezawodny rozmiar - bo to Cię oszuka.
Czteroliniowa rzecz - to całkiem proste. 4-plikowa rzecz - po prostu nie wiem, jak można to zrobić niezawodnie i z równomierną dystrybucją bez uprzedniego rozpakowania archiwum, aby uzyskać jego nieskompresowany rozmiar. Nie sądzę, żebyś mógł, bo próbowałem.
Jednak to, co można zrobić, to ustawić maksymalny rozmiar dla plików wyjściowych split, i upewnij się, że te zawsze są łamane na bariery płytowych. Możesz to łatwo zrobić. Oto mały skrypt, który zrobi to poprzez rozpakowanie gzip
archiwum i przesłanie zawartości przez kilka jawnych dd
buforów potoku z konkretnymi count=$rpt
argumentami, przed przekazaniem tego lz4
do dekompresji / ponownej kompresji każdego pliku w locie. Wrzuciłem także kilka małych tee
sztuczek na fajce, aby wydrukować ostatnie cztery wiersze dla każdego segmentu na stderr.
( 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
)
To będzie trwać, dopóki nie obsłuży wszystkich danych wejściowych. Nie próbuje podzielić go na pewien procent - którego nie może uzyskać - ale dzieli go na maksymalną liczbę nieprzetworzonych bajtów na podział. Poza tym duża część twojego problemu polega na tym, że nie możesz uzyskać wiarygodnego rozmiaru w swoim archiwum, ponieważ jest ono zbyt duże - cokolwiek robisz, nie rób tego ponownie - spraw, aby podziały były mniejsze niż 4 gb , może. Przynajmniej ten mały skrypt pozwala to zrobić bez konieczności zapisywania nieskompresowanego bajtu na dysku.
Oto krótsza wersja pozbawiona zasadniczych elementów - nie dodaje się do wszystkich elementów raportu:
( 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
Robi te same rzeczy, co pierwsze, w większości nie ma nic więcej do powiedzenia na ten temat. Ponadto jest mniej bałaganu, więc może łatwiej jest zobaczyć, co się dzieje.
Chodzi IFS=
o to, aby obsłużyć jedną read
linię na iterację. My, read
ponieważ potrzebujemy, aby nasza pętla zakończyła się, gdy zakończy się wejście. Zależy to od wielkości twojego rekordu - który w twoim przykładzie wynosi 354 bajtów na. Stworzyłem gzip
archiwum 4+ GB z losowymi danymi w celu przetestowania.
Losowe dane otrzymano w ten sposób:
( 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
... ale może nie musisz się tym tak bardzo przejmować, ponieważ masz już wszystkie dane. Powrót do rozwiązania ...
Zasadniczo pigz
- który wydaje się dekompresować nieco szybciej niż robi to zcat
- odpompowuje nieskompresowany strumień i dd
buforuje dane wyjściowe do bloków zapisu o rozmiarze dokładnie wielokrotności 354 bajtów. Pętla będzie po każdej iteracji do testu, który wejście jest wciąż przybywających, co będzie potem co przed kolejnym nazywa się czytać bloki formowany specjalnie na wielokrotnością 354 bajtów - do synchronizacji z buforowania procesu - na czas. Będzie jeden krótki odczyt na każdą iterację z powodu początkowej - ale to nie ma znaczenia, ponieważ drukujemy to w naszym procesie kolekcjonowania.read
$line
printf
printf
lz4
dd
dd
read $line
lz4
Skonfigurowałem go tak, aby każda iteracja odczytywała około 1 GB nieskompresowanych danych i kompresowała ten strumień do około 650 Mb lub mniej więcej. lz4
jest znacznie szybszy niż jakakolwiek inna przydatna metoda kompresji - dlatego wybrałem ją tutaj, ponieważ nie lubię czekać. xz
prawdopodobnie jednak wykonałby znacznie lepszą robotę przy kompresji. Jedną z rzeczy lz4
jest to, że często może dekompresować przy prędkościach zbliżonych do pamięci RAM - co oznacza, że wiele razy można dekompresować lz4
archiwum tak szybko, jak i tak można by je zapisać do pamięci.
Ten duży wykonuje kilka raportów dla każdej iteracji. Obie pętle wydrukują dd
raport o liczbie przesłanych nieprzetworzonych bajtów oraz prędkości i tak dalej. Wielka pętla wypisze również ostatnie 4 wiersze danych wejściowych na cykl i liczbę bajtów dla tego samego, a następnie jeden ls
z katalogu, do którego piszę lz4
archiwa. Oto kilka rund wyników:
/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
?