Разделение файлов журналов, сжатых с помощью gzip, без сохранения разархивированных файлов на диске

У меня есть повторяющаяся задача разбить набор больших (около 1-2 ГиБ каждый) gzip-файлов журнала Apache на несколько частей (скажем, куски по 500 тыс. строк). Окончательные файлы должны быть снова сжаты gzip, чтобы ограничить использование диска.

В Linux я обычно делаю:

zcat biglogfile.gz | split -l500000

Результирующие файлы будут называться xaa, xab, xac и т. д. Итак, я делаю:

gzip x*

Эффект этого метода заключается в том, что в качестве промежуточного результата эти огромные файлы временно сохраняются на диске. Есть ли способ избежать использования этого промежуточного диска?

Могу ли я (подобно тому, что делает xargs) разделить вывод через команду (например, gzip) и повторно сжать вывод на лету? Или я смотрю в неправильном направлении, и есть ли лучший способ сделать это?

Спасибо.


person Niels Basjes    schedule 18.10.2010    source источник
comment
Я бы посмотрел на реализацию функциональности разделенного стиля на языке сценариев, где вы могли бы записывать строки прямо в файлы, сжатые gzip.   -  person a'r    schedule 18.10.2010


Ответы (4)


Вы можете использовать параметр split --filter, как описано в руководстве например

zcat biglogfile.gz | split -l500000 --filter='gzip > $FILE.gz'

Изменить: неизвестно, когда была введена опция --filter, но, согласно комментариям, она не работает в core utils 8.4.

person jimkont    schedule 10.07.2014
comment
Спасибо. Я думаю, что использование функции разделения, которая была разработана для выполнения такого рода операций, всегда лучше, чем собственный код. - person Niels Basjes; 10.08.2014
comment
очень хорошо, но обратите внимание, что разделение coreutils 8.4 не имеет filter argumnet - person zach; 03.03.2015

Сценарий, подобный следующему, может быть достаточным.

#!/usr/bin/perl
use PerlIO::gzip;

$filename = 'out';
$limit = 500000;

$fileno = 1;
$line = 0;

while (<>) {
    if (!$fh || $line >= $limit) { 
        open $fh, '>:gzip', "$filename_$fileno"; 
        $fileno++;
        $line = 0; 
    }
    print $fh $_; $line++;
}
person a'r    schedule 18.10.2010
comment
Спасибо, ваш быстрый пример мне очень помог. С двумя небольшими исправлениями (первая строка должна начинаться с #!/, а после $fileno++ требуется дополнительная $line=0) это работало достаточно хорошо для моих целей. - person Niels Basjes; 20.10.2010
comment
Спасибо. Я добавил их в сценарий для полноты картины. - person a'r; 20.10.2010

В случае, если людям нужно сохранить 1-й ряд (заголовок) в каждой из частей

zcat bigfile.csv.gz | tail -n +2 | split -l1000000 --filter='{ { zcat bigfile.csv.gz | head -n 1 | gzip; gzip; } > $FILE.gz; };'

Я знаю, что это немного неуклюже. Я ищу более элегантное решение.

person Zach    schedule 11.11.2020

Существует zipsplit, но он использует алгоритм zip, а не алгоритм gzip.

person Tony Miller    schedule 18.10.2010