сортировать многострочные записи с помощью awk - PullRequest
0 голосов
/ 26 июня 2018

У меня есть файл с записями, которые выглядят так:

nad9
   abie_by_ctai_prots   contig_4729                         808,  1393     1,196   abie_by_ctai_prots_1_196
   abie_by_wmir_prots   contig_4729                         811,  1363     2,187   abie_by_wmir_prots_2_187
   abie_by_gbil_prots   contig_4729                         808,  1393     1,196   abie_by_gbil_prots_1_196
   abie_by_atha_prots   contig_4729                         808,  1363     1,186   abie_by_atha_prots_1_186

ND2
   abie_by_ctai_prots   contig_1280                        9618, 11661     0,182   abie_by_ctai_prots_0_182
   abie_by_ctai_prots   contig_9528                         770,   959   427,490   abie_by_ctai_prots_427_490
   abie_by_ctai_prots   contig_6628                        5874,  2217   182,429   abie_by_ctai_prots_182_429

ccmB
   abie_by_ctai_prots   contig_334                        39851, 39218     0,212   abie_by_ctai_prots_0_212
   abie_by_wmir_prots   contig_334                        39842, 39218     2,211   abie_by_wmir_prots_2_211
   abie_by_gbil_prots   contig_334                        39851, 39218     0,212  

Я хочу отсортировать записи по именам генов (первая строка записи). Вывод должен выглядеть так:

ND2
   abie_by_ctai_prots   contig_1280                        9618, 11661     0,182   abie_by_ctai_prots_0_182
   abie_by_ctai_prots   contig_9528                         770,   959   427,490   abie_by_ctai_prots_427_490
   abie_by_ctai_prots   contig_6628                        5874,  2217   182,429   abie_by_ctai_prots_182_429

ccmB
   abie_by_ctai_prots   contig_334                        39851, 39218     0,212   abie_by_ctai_prots_0_212
   abie_by_wmir_prots   contig_334                        39842, 39218     2,211   abie_by_wmir_prots_2_211
   abie_by_gbil_prots   contig_334                        39851, 39218     0,212   abie_by_gbil_prots_0_212

nad9
   abie_by_ctai_prots   contig_4729                         808,  1393     1,196   abie_by_ctai_prots_1_196
   abie_by_wmir_prots   contig_4729                         811,  1363     2,187   abie_by_wmir_prots_2_187
   abie_by_gbil_prots   contig_4729                         808,  1393     1,196   abie_by_gbil_prots_1_196
   abie_by_atha_prots   contig_4729                         808,  1363     1,186   abie_by_atha_prots_1_186

Я пробовал этот код безуспешно:
vilde$ awk '{ RS = ""; FS = "\n"} {print $0}' |sort filename.txt

Это дает мне вывод, похожий на этот:

(empty line)    
(empty line)
(empty line)  
abie_by_ctai_prots   contig_4729                         808,  1393     1,196   abie_by_ctai_prots_1_196
abie_by_wmir_prots   contig_4729                         811,  1363     2,187   abie_by_wmir_prots_2_187
abie_by_gbil_prots   contig_4729                         808,  1393     1,196   abie_by_gbil_prots_1_196
abie_by_atha_prots   contig_4729                         808,  1363     1,186   abie_by_atha_prots_1_186
ND2   
ccmB
nad9

Мне кажется, что это сортировка по полям, а не по записям, но я не понимаю, почему или как это изменить.

Ответы [ 3 ]

0 голосов
/ 26 июня 2018

Если вы вводите текстовый файл (например, в нем нет нулевых байтов), вы можете выполнить некоторую предварительную / постобработку. Мой Perl немного ржавый, но вот простой способ заменить каждую новую строку в записи нулевым байтом, затем использовать сортировку, а затем вернуть ее в новую строку.

perl -e 'while(<>){ chop; $p .=  ($_ eq "") ? "\n" : "\000" ; 
    print $p; $p=$_; }' input.txt | sort | perl -pe 's/\000/\n/g'

Возможно, немного чище, чтобы написать это как:

< input.txt perl -000 -lape 's/\n/\000/g' | 
    sed '/^$/d' | sort | 
    perl -ne 's/\000/\n/g; print $_ . "\n"'

Использование абзаца (а не всего файла) - это бессмысленная попытка включить большие файлы, не помещая все в память. (Бессмысленно, потому что, если проблема в том, что размер данных будет достаточным, чтобы вызвать проблемы, то sort будет задыхаться.)

0 голосов
/ 26 июня 2018

Ваша командная строка в вашем вопросе, по-видимому, не обеспечивает ввод команды awk, поэтому вы просто сортируете отдельные строки вашего входного файла. Но вы на правильном пути с RS="".

Насколько мне известно, большинство реализаций сортировки не будут обрабатывать многострочный ввод для отдельных записей. Но ваши записи выглядят так, как если бы awk работал бы хорошо, поэтому я думаю, что мой подход заключается в том, чтобы использовать конвейер для преобразования новых строк в записях, чтобы позволить сортировать записи, а затем преобразовывать их обратно после сортировки. Как это:

$ awk -v RS= '{gsub(/\n/,"#")} 1' input.txt | sort | awk '{gsub(/#/,"\n")} 1'

Обратите внимание, что это не помещает пустые строки между записями. Если вам это нужно, замените окончательный 1 на: {print $0 ORS}.

0 голосов
/ 26 июня 2018

Есть несколько способов сделать это:

Небольшой файл: Если вы хотите отсортировать небольшой файл, вы можете использовать GNU awk для этого и использовать PROCINFO["sorted_in"]="@ind_str_asc", что даст вам обход массива в порядке возрастания индекса.

awk 'BEGIN{RS=""; ORS="\n\n"; FS="\n"
           PROCINFO["sorted_in"]="@ind_str_asc" }
     {a[$1]=$0}
     END{for(i in a) { print a[i] } }' <inputfile> > <outputfile>

Огромный файл: Если вы хотите сделать это с очень большим файлом, то awk его захлебнет, поэтому вам придется сделать это немного по-другому с некоторыми awk, sort и cat прочее. Идея состоит в том, чтобы создать много файлов с правильным именем, а затем отсортировать файлы и отследить их:

#!/usr/bin/env bash
inputfile=$1
outputfile=$2

dir=$(mktemp -d)
awk -v dir=$dir 'BEGIN{RS=""; ORS="\n\n"; FS="[[:blank:]]*\n"}
     { fname=dir"/"$1; print $0 > fname; close(fname) }' $inputfile
export LC_ALL=C
files=( $dir/* )
sort <<< ${files[*]} | xargs cat > $outputfil
rm -rf $dir

или вы можете просто использовать один большой трубопровод:

awk 'BEGIN{RS="";FS="\n";OFS="|"}{gsub(FS,OFS)}1' <inputfile> | sort \
   | awk 'BEGIN{ORS="\n\n";OFS="\n";FS="\\|"}{gsub(FS,OFS)}1' > <outputfile>

примечание: Я предполагаю, что в вашем файле нет Windows \r\n. Исходные данные показывают, что это так.

Полезные ссылки:

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