unix-сплит огромный.GZ файл по строке

Я уверен, что кто - то имел ниже нужно, что это быстрый способ разделить огромный .GZ файл построчно? Базовый текстовый файл имеет 120million строк. У меня недостаточно места на диске для gunzip всего файла сразу, поэтому мне было интересно, знает ли кто-нибудь сценарий bash/perl или инструмент, который может разделить файл (либо .GZ или внутренний .txt) в 3x 40mn линейных файлов. т. е. называя это как:

    bash splitter.sh hugefile.txt.gz 4000000 1
 would get lines 1 to 40 mn    
    bash splitter.sh hugefile.txt.gz 4000000 2
would get lines 40mn to 80 mn
    bash splitter.sh hugefile.txt.gz 4000000 3
would get lines 80mn to 120 mn

возможно, делает ряд из них решением или gunzip-c требует достаточно места для распаковки всего файла (т. е. исходной проблемы): gunzip-c hugefile.формат txt.ГЗ | глава 4000000

примечание: Я не могу получить дополнительный диск.

спасибо!

5
задан toop
источник

6 ответов

как это лучше зависит от того, что вы хотите:

  • вы хотите извлечь одну часть большого файла?
  • или вы хотите создать все детали за один раз?

если вы хотите одна часть файла ваша идея использовать gunzip и head - Это верно. Вы можете использовать:

gunzip -c hugefile.txt.gz | head -n 4000000

это выведет первые 4000000 строк на стандартный выход - вы, вероятно, захотите добавить еще одну трубу чтобы действительно что-то сделать с данными.

чтобы получить другие части, вы будете использовать комбинацию head и tail, например:

gunzip -c hugefile.txt.gz | head -n 8000000 |tail -n 4000000

чтобы получить второй блок.

, возможно, делает ряд из них решение или будет gunzip-c требуется достаточно места для распаковки всего файла

нет,gunzip -c не требует дискового пространства - он делает все в памяти, а затем передает его на стандартный вывод.


если вы хотите создать все части за один раз, эффективнее создавать их все одной командой, потому что тогда входной файл читается только один раз. Одним из хороших решений является использование split; Подробнее см. ответ Джима Макнамары.

11
отвечен sleske 2016-09-07 07:19:58
источник

труба для разделения используйте gunzip-c или zcat, чтобы открыть файл

gunzip -c bigfile.gz | split -l 400000

добавить выходные спецификации в команду split.

18
отвечен jim mcnamara 2012-01-23 16:41:30
источник

когда вы работаете над (не перематываемым) потоком, вы захотите использовать форму' +N ' хвоста, чтобы получить строки, начиная с строки N и далее.

zcat hugefile.txt.gz | head -n 40000000
zcat hugefile.txt.gz | tail -n +40000001 | head -n 40000000
zcat hugefile.txt.gz | tail -n +80000001 | head -n 40000000
6
отвечен zgpmax 2012-01-23 11:33:16
источник

Я хотел бы рассмотреть возможность использования split.

разбить файл на куски

4
отвечен Michael Krelin - hacker 2012-02-20 00:22:25
источник

вот скрипт python для открытия глобированного набора файлов из каталога, gunzip их, если необходимо, и чтения их построчно. Он использует только пространство, необходимое в памяти для хранения имен файлов и текущей строки, а также немного накладных расходов.

#!/usr/bin/env python
import gzip, bz2
import os
import fnmatch

def gen_find(filepat,top):
    for path, dirlist, filelist in os.walk(top):
        for name in fnmatch.filter(filelist,filepat):
            yield os.path.join(path,name)

def gen_open(filenames):
    for name in filenames:
        if name.endswith(".gz"):
            yield gzip.open(name)
        elif name.endswith(".bz2"):
            yield bz2.BZ2File(name)
        else:
            yield open(name)

def gen_cat(sources):
    for s in sources:
        for item in s:
            yield item

def main(regex, searchDir):
    fileNames = gen_find(regex,searchDir)
    fileHandles = gen_open(fileNames)
    fileLines = gen_cat(fileHandles)
    for line in fileLines:
        print line

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Search globbed files line by line', version='%(prog)s 1.0')
    parser.add_argument('regex', type=str, default='*', help='Regular expression')
    parser.add_argument('searchDir', , type=str, default='.', help='list of input files')
    args = parser.parse_args()
    main(args.regex, args.searchDir)

команда print line будет посылать каждую строку в std out, так что вы можете перенаправить в файл. В качестве альтернативы, если вы сообщите нам, что вы хотите сделать со строками, я могу добавить его в скрипт python, и вам не нужно оставьте куски файла лежать вокруг.

2
отвечен Spencer Rathbun 2012-01-23 13:39:57
источник

вот программа perl, которая может использоваться для чтения stdin и разделения строк, передавая каждый комок в отдельную команду, которая может использовать переменную оболочки $SPLIT для маршрутизации ее в другое место назначения. В вашем случае это будет вызвано с помощью

zcat hugefile.txt.gz | perl xsplit.pl 40000000 'cat > tmp$SPLIT.txt; do_something tmp$SPLIT.txt; rm tmp$SPLIT.txt'

извините обработка командной строки немного kludgy но вы получите идею.

#!/usr/bin/perl -w
#####
# xsplit.pl: like xargs but instead of clumping input into each command's args, clumps it into each command's input.
# Usage: perl xsplit.pl LINES 'COMMAND'
# where: 'COMMAND' can include shell variable expansions and can use $SPLIT, e.g.
#   'cat > tmp$SPLIT.txt'
# or:
#   'gzip > tmp$SPLIT.gz'
#####
use strict;

sub pipeHandler {
    my $sig = shift @_;
    print " Caught SIGPIPE: $sig\n";
    exit(1);
}
$SIG{PIPE} = \&pipeHandler;

my $LINES = shift;
die "LINES must be a positive number\n" if ($LINES <= 0);
my $COMMAND = shift || die "second argument should be COMMAND\n";

my $line_number = 0;

while (<STDIN>) {
    if ($line_number%$LINES == 0) {
        close OUTFILE;
        my $split = $ENV{SPLIT} = sprintf("%05d", $line_number/$LINES+1);
        print "$split\n";
        my $command = $COMMAND;
        open (OUTFILE, "| $command") or die "failed to write to command '$command'\n";
    }
    print OUTFILE $_;
    $line_number++;
}

exit 0;
2
отвечен Liudvikas Bukys 2012-01-23 20:54:43
источник

Другие вопросы bash linux perl shell unix