【问题标题】:Improve the speed of my bash code提高我的 bash 代码的速度
【发布时间】:2012-01-21 07:14:18
【问题描述】:

以下是我需要处理的文件格式:

@HWI-ST150_0129:2:1:4226:2616#0/1
CATCTTTTCTCTTAACTTCCATGATGGTACATCTTTTGATTTTTTTTTAATAACGTCTTTGACAGCTTAAATTCTTTTTCAAAATC
+HWI-ST150_0129:2:1:4226:2616#0/1
d\dddddaddbcad^\^a\]ZZZ_`]\VYa_bZ^_^\YX\X`eeeeffffffefffeeefffefffeeffBBBBBBBBBBBBBBBB

基本上我需要做的是: 1.每4行挑出一次;并在字符串的 END 处修剪所有可能的尾随“B”。

2.如果修剪后左侧部分> 70%的整个字符串,则:在第4行训练“B”的每2行修剪对应部分。

3.然后只附加所有 4 行,第 2 行和第 4 行被修剪。

所以预期的结果如下:

@HWI-ST150_0129:2:1:4226:2616#0/1
CATCTTTTCTCTTAACTTCCATGATGGTACATCTTTTGATTTTTTTTTAATAACGTCTTTGACAGCTTAA
+HWI-ST150_0129:2:1:4226:2616#0/1
d\dddddaddbcad^\^a\]ZZZ_`]\VYa_bZ^_^\YX\X`eeeeffffffefffeeefffefffeeff

我写了一个像这样的脚本:

for((a=1;a<=8000000;a++))
do
  if (($a%4==0))
  then  
      b=`cat $FILENAME|head -$a|tail -1|sed 's/\(.\)B*$/\1/g'|wc -c`
      d=`cat $FILENAME|head -$a|tail -1|wc -c`
      if (( 10*$b/$d>= 7 ))
      then
          cat $FILENAME|head -$(($a-3))|tail -1
          cat $FILENAME|head -$(($a-2))|tail -1|cut -b 1-$(($b-1))
          cat $FILENAME|head -$(($a-1))|tail -1
          cat $FILENAME|head -$a|tail -1|sed 's/\(.\)B*$/\1/g'
      fi
  fi
done >> /home/xxx/$DIRNAME/$FILENAME

我认为我更喜欢 bash 代码,仅仅是因为它速度快(?)。但是,当我运行此代码时,考虑 8000000 行时会很慢。另外,也许我在代码中使用了太多“猫”?

快速,我的意思是说,当使用拆分命令拆分 GB 级大文件时;它超级超级快。 (分裂的机制是什么?)

有什么提高速度的建议吗?

【问题讨论】:

  • 在这个脚本中你根本不需要 cat。 head、tail、sed 和 wc 都将文件名作为参数。你可以head -... $FILENAME | tail -1 | cut.....partmaps.org/era/unix/award.html ;)。此外,对于代码审查 stackexchange 站点来说,这可能是一个更好的问题。
  • 我同意@chown。 cat 当您只是将输出通过管道传输到 head 时,实际上并不需要。
  • 谢谢大家。嗯你是对的。所以也许“猫”是限速因素......
  • 是的,因为如果您考虑一下,如果您的文件有 800,000 行,那么 cat 会仔细阅读所有这些,只是将其传送到 head,然后获取前 10 行。更简单的方法是在文件上执行 head 以在 10 行后停止阅读。
  • @Jaypal:您声称cat 将在将所有行传送到head 之前读取它们。那不是真的。 cat 将读取一行,(或者实际上它会填充 X 字节的缓冲区,但我正在简化,请耐心等待)然后将这一行写入 head。然后它将读取另一行,并将该行写入head,依此类推。当head 已读取 10 行时,它将退出,这会将 SIGPIPE 发送到 cat 并在读取所有行之前很久就终止它。见en.wikipedia.org/wiki/SIGPIPE

标签: performance bash


【解决方案1】:

改变你的逻辑,让它像这样工作:

1) 读入 4 行。

2) 处理您读入的 4 行。

3) 写出你的处理结果

4) 重复。

您的代码每次通过文件六次。您只需经历一次即可。

【讨论】:

    【解决方案2】:

    我认为问题的一部分可能是最外面的 for 循环的每次迭代,你都会对整个文本文件进行 catting/heading/whatevering...我想这将是瓶颈的根源。

    删除 cat 可能不会让它更快,因为你每次都在它上面调用其他 unix 命令。

    您可能希望寻找一种解决方案,该解决方案可以只读取文件一次并产生必要的输出,而不是读取 8,000,000 * 6 次。 (1 对 48,000,000!:))

    这就是想法:

    f = OPEN_FILE() //Some file descriptor
    out_f = NEW_FILE_FOR_WRITING() //open some file to write to
    while not_eof(f):
        cur_window = read_four_lines(f) //Get four lines from the text thing
        modified_block = do_stuff(cur_window) //Do your processing in a different function
        write(out_f,modified_block) //Write the modified stuff to the output file
    

    我不确定您最喜欢哪种语言,但这应该不会太难。我想它可以在 bash 脚本中进行一些修改。

    【讨论】:

      【解决方案3】:

      您可以使用~sed 更改每4 行。如果您的意图是修剪 INPUT_FILE 的每 4 行的所有尾随 B,那么只需执行 -

      例如:

      [jaypal:~/Temp] cat file
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      
      [jaypal:~/Temp] sed '0~4 s/[0-9]/bbbb/' file
      1
      2
      3
      bbbb
      5
      6
      7
      bbbb
      9
      10
      

      【讨论】:

        【解决方案4】:

        大卫是对的。多次解析同一个大文件确实效率低下。此外,调用所有这些外部程序也会降低性能。

        这是 David 在 bash 中提供的逻辑的简单实现,每个循环只有一个外部命令:

        #!/bin/bash
        DONE=false
        until $DONE ; do
        read -r LINE1 || DONE=true
        read -r LINE2 || DONE=true
        read -r LINE3 || DONE=true
        read -r LINE4 || DONE=true
        
        NEWLINE4=`echo $LINE4 |sed 's/\(.\)B*$/\1/g'`
        NEWLINE2=${LINE2:0:${#NEWLINE4}}
        
        echo $LINE1
        echo $NEWLINE2
        echo $LINE3
        echo $NEWLINE4
        
        done
        

        它非常简单,并且有一些容易修复的陷阱(它在末尾打印 4 个空行)。这段代码应该比你的第一个版本快很多倍。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-16
          • 2021-10-14
          • 1970-01-01
          相关资源
          最近更新 更多