首页 > 解决方案 > awk 和 sed 的管道命令太慢了!关于如何让它更快地工作的任何想法?

问题描述

我正在尝试将包含具有脚手架编号的列和具有相应单个站点的另一个列的文件转换为列出范围内站点的床文件。例如,这个文件($indiv.txt):

SCAFF      SITE
1           1
1           2
1           3
1           4
1           5 
3           1
3           2
3           34
3           35
3           36

应转换为$indiv.bed

SCAFF      SITE-START   SITE-END
1              1            5
3              1            2
3              34           36

目前,我正在使用以下代码,但它非常慢所以我想问是否有人能想出一个更快的方法?

命令:

for scaff in $(awk '{print $1}' $indiv.txt | uniq)
do
      awk -v I=$scaff '$1 == I { print $2 }' $indiv.txt | awk 'NR==1{first=$1;last=$1;next} $1 == last+1 {last=$1;next} {print first,last;first=$1;last=first} END{print first,last}' | sed "s/^/$scaff\t/" >> $indiv.bed
done

描述:

awk '{print $1}' $indiv.txt | uniq  #outputs a list with the unique scaffold numbers 

awk -v I=$scaff '$1 == I { print $2 }' $indiv.txt #extracts the values from column 2 if the value in the first column equals the variable $scaff

awk 'NR==1{first=$1;last=$1;next} $1 == last+1 {last=$1;next} {print first,last;first=$1;last=first} END{print first,last}' #converts the list of sequential numbers into ranges as described here: https://stackoverflow.com/questions/26809668/collapse-sequential-numbers-to-ranges-in-bash

sed "s/^/$scaff\t/" >> $indiv.bed #adds a column with the respective scaffold number and then outputs the file into $indiv.bed

提前非常感谢!

标签: bashawk

解决方案


为输入的每一行调用多个程序必须很慢。通常最好找到一种方法来处理一次调用中的所有行。

我会使用 Perl:

tail -n+2 indiv.txt \
| sort -u -nk1,1 -nk2,2 \
| perl -ane 'END {print " $F[1]"}
             next if $p[0] == $F[0] && $F[1] == $p[1] + 1;
             print " $p[1]\n@F";
             } continue { @p = @F;' > indiv.bed

前两行对输入进行排序,以便组始终相邻(如果您的输入已经以这种方式排序,则可能不需要);perl than 读取行,-a将每一行拆分为@F数组,该@p数组用于保留前一行:如果当前行具有相同的一个元素并且第二个元素大于 1,我们转到continue仅存储的部分当前行变为@p. 否则,我们打印上一节的最后一个元素和当前节的第一行。该END块负责打印最后一节的最后一个元素。

对于只有一个成员的部分,输出与您的不同。


推荐阅读