【问题标题】:piping commands of awk and sed is too slow! any ideas on how to make it work faster?awk 和 sed 的管道命令太慢了!关于如何让它更快地工作的任何想法?
【发布时间】:2019-09-02 12:26:02
【问题描述】:

我正在尝试将包含具有支架编号的列和具有相应单个站点的另一个列的文件转换为列出范围内站点的床文件。例如,这个文件($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

提前非常感谢!

【问题讨论】:

  • 也许stackoverflow.com/a/38627863/874188 可以帮助你稍微理顺这个椒盐卷饼的逻辑。
  • 致所有“搁置”的人:问题不是说“这不起作用”,而是“它很慢”。这样的问题在这里真的是题外话吗?代码运行良好并显示了预期的输出。
  • 另外,这里有一个 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;'
  • 使用单个awk 调用的解决方案;假设数据在文件scaff.txt;在读取每一行时应用一组测试/操作:awk 'function print_scaff () { if ( scaff != -9 ) { printf "%-10s %-15s %-10s\n",scaff,start,end } } $1 == "SCAFF" { printf "%-10s %-15s %-10s\n","SCAFF","SITE-START","SITE-END"; scaff=-9; next } $1 != scaff { print_scaff() ; scaff=$1; start=$2; end=$2; next } $2 != (end+1) { print_scaff(); start=$2; end=$2 ; next } $2 == (end+1) { end=$2 ; next } { print_scaff() } END { print_scaff() }' scaff.txt 注意:必须去掉 cmets 以适应此注释块
  • @mernster 主要目标:1) 消除对数据文件的(可能大量)重复扫描,以及 2) 消除由各种管道调用的(可能大量)子流程跨度>

标签: bash awk


【解决方案1】:

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

我会使用 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 比读取行,-a 将每一行拆分为 @F 数组,@p 数组用于保留 previous 行:如果当前行具有相同的第一个元素并且第二个元素大于 1,我们转到 continue 部分,它将当前行存储到 @p 中。否则,我们打印上一节的最后一个元素和当前节的第一行。 END 块负责打印最后一节的最后一个元素。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 2015-05-30
    • 1970-01-01
    • 2023-02-16
    • 2017-04-23
    相关资源
    最近更新 更多