提高我的bash代码的速度

时间:2011-11-29 00:36:32

标签: performance bash

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

@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行为第4行的“B”修剪对应物。

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行时,它很慢。另外,也许我在代码中使用了“cat”太多了?

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

有什么建议可以提高速度吗?

4 个答案:

答案 0 :(得分:2)

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

1)读入4行。

2)处理你读过的4行。

3)写出处理结果

4)重复。

您的代码在每次传递时都会通过该文件六次。你只需要为所有事情完成一次。

答案 1 :(得分:1)

我认为问题的一部分可能是最外面的for循环的每次迭代,你将要抓住/标题/无论整个文本文件......我想这将是瓶颈的来源。

删除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脚本中可以进行一些修改。

答案 2 :(得分:0)

您可以使用~sed的每一行进行更改。如果您打算修剪INPUT_FILE每四行的所有尾随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

答案 3 :(得分:0)

大卫是对的。多次解析同一个大文件真的很低效。此外,调用所有这些外部程序也会破坏性能。

这是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条空行),很容易修复。此代码应该比第一个版本快许多倍。