разделить большой файл разделителем памяти - PullRequest
1 голос
/ 24 сентября 2019

Я хочу разделить большой файл на множество файлов на основе разделителя.Разделитель, который я нацеливаю в моем входном файле: // (двойная косая черта в новой строке).Часть моего файла выглядит как

..
...
 7141 gatttaggca gtgaaaactt agtagccgac aaggtgaaag atgccgagaa tgtactaagg
 7201 gtaaaggcag ctaaaacaga ctttaccgat agcaccaacc tatcggtcat cactcaagac
 7261 ggaggctttt atagctttga ggtgagttat cacaccacgc cacaacctct taccattgat
 7321 tttggtagag gaatgcccca aggcaataat gtgaaatcgg atattctctt ttctgacaca
 7381 ggctgggaat cacctgcggt agcacagatt attatgtcgt ctatct
//



LOCUS       KE150251                6962 bp    DNA     linear   CON 
14-JUN-2013
DEFINITION  Capnocytophaga granulosa ATCC 51502 genomic scaffold
        acFDk-supercont1.18/ whole genome shotgun sequence.
 ...
..

Я также хочу включить эти косые черты в качестве последней строки сгенерированных файлов.

Мне не удалось сделать это с помощью csplit на моем Mac, и в итогесо следующим скриптом awk:

awk -v RS='^//' '{ outfile = "output_file_" NR; print > outfile}' Input.gbk 

Но я получаю следующую ошибку:

awk(56213,0x7fffb585b3c0) malloc: *** 
mach_vm_map(size=18446744071562067968) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
awk: out of memory in readrec 1
source line number 1

Спасибо за ваши предложения!

Ответы [ 4 ]

2 голосов
/ 24 сентября 2019

Лучше использовать библиотеку для разбора больших файлов GenBank.Вот один из способов использования Bio :: SeqIO :: genbank , который возвращает объекты Bio :: Seq и записывает их в отдельные файлы по отображаемому идентификатору.Поместите следующее в файл с именем split_genbank.pl:

#!/usr/bin/env perl

use strict;
use warnings;

use Bio::SeqIO::genbank;

my $stream = Bio::SeqIO->new(-file => $ARGV[0], -format => 'GenBank');

while ( my $seq = $stream->next_seq ) {
    my $id = $seq->display_id();

    my $out = Bio::SeqIO->new(-format => 'GenBank', -file => ">$id.gbk");
    $out->write_seq($seq);
}

Затем вызовите его, используя:

perl split_genbank.pl input.gbk
1 голос
/ 24 сентября 2019

Установив RS, вы заставляете awk читать данные до разделителя.Вы говорите, что ваш файл большой, поэтому возможно, что результирующие записи больше, чем память, доступная для awk для обработки.

Для вашего приложения вы можете использовать значение по умолчанию для RS и вычислить эффективный NR:вручную, увеличивая счетчик всякий раз, когда читается разделитель:

awk '
    BEGIN {
        pre = "output_file_"
        n = 1
        outfile = pre n
    }
    {
        print > outfile
    }
    /^\/\// {
        close(outfile)
        n++
        outfile = pre n
    }
' Input.gbk
1 голос
/ 24 сентября 2019

Я полагаю, что поскольку вы НЕ закрыли файлы (новые выходные файлы), они поглощают память.Не могли бы вы попробовать один раз.

awk -v RS='^//' '{close(outfile)} {outfile = "output_file_" NR; print > outfile}' Input.gbk

РЕДАКТИРОВАТЬ: еще одну попытку с другим подходом.Поскольку я считаю, что в вашем файле много строк между //, поэтому память заполняется на RS, поэтому лучше использовать подход с использованием флага, а не RS.

awk -v outfile="output_file_1" -v count=1 '/^\/\//{print > outfile; close(outfile);outfile = "output_file_" ++count;next} {print > (outfile)}' Input.gbk

Объяснение вышеуказанного подхода: Проверка строки, начинающейся с // и значения приращения в имени выходного файла и значения сброса переменной имени выходного файла, также я закрываю выходной файл здесь, иначеВы можете получить сообщение об ошибке: слишком много файлов открыто в фоновом режиме.

0 голосов
/ 28 сентября 2019

Так как у вас есть доступ к GNU csplit.Вы можете использовать его:

csplit Input.gbk '/^\/\//+1' '{*}'

Ваша исходная команда не работает, потому что csplit ожидает регулярное выражение, а не фиксированную строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...