每 10000 个数字(不是行)分割文件

每 10000 个数字(不是行)分割文件

我有一个如下所示的文件:

chr19   61336212        +       0       0       CG      CGT    
chr19   61336213        -       0       0       CG      CGG    
chr19   61336218        +       0       0       CG      CGG    
chr19   61336219        -       0       0       CG      CGC    
chr19   61336268        +       0       0       CG      CGG    
chr19   61336269        -       0       0       CG      CGA    
chr19   61336402        +       0       0       CG      CGG    
chr19   61336403        -       0       0       CG      CGT    

我想将这个文件拆分为第二个字段的每 10000 个间隔(不是行,而是数字间隔)。因此,对于这个文件,我想从第一行(包含 61336212 的行)拆分到具有或最多 61346211 (61336212+9999)的行,然后从 61346212 拆分到 61356211,依此类推。正如您所看到的,第二个字段/列中的数字未“填充”。

有没有办法做到这一点?

答案1

awk 'NR==1 {n=$2}
     {
       file = sprintf("file.%.4d", ($2-n)/10000)
       if (file != last_file) {
         close(last_file)
         last_file = file
       }
       print > file
     }'

会写到file.0000, ... (其中file.0001的数字是第一行的数字)。int(($2-n)/10000)n$2

请注意,一旦停止写入文件,我们就会关闭文件,否则,在数百个文件后,您将达到同时打开文件数量的限制(GNUawk可以解决该限制,但性能会迅速下降)。

我们假设这些数字总是在上升。

答案2

破解单行版本。也许更适合代码高尔夫不过比这个论坛。这会生成 split1、split2、split3 等文件名。

awk '{if($2>b+9999){a++;b=$2}print >"split" a}' file.txt

要使输出文件名为 split001、split002、split003,需要额外的操作sprintf

awk '{if($2>b+9999){a++;b=$2}print >sprintf("split%03d",a)}' file.txt

为了避免 @Stéphane Chazelas 发现的 gawk 速度减慢问题,请使用 perl:

perl -ne '(undef,$a)=split(/\s+/,$_);if($a>$b+9999){$c++;$b=$a}open(D,sprintf(">>ysplit%03d",$c));print D' <file.txt

答案3

#!/bin/bash
first=$( head -n1 file | awk -F" +" '{print $2}' )
last=$( tail -n1 file | awk -F" +" '{print $2}' )
for (( i=$first ; i<=$last ; i=i+10000 )) ; do
   awk -v start=$i -v end=$(($i+10000)) 'BEGIN { FS == " +" } { if ( $2 >= start && $2 < end ) print $0 }' file \
   >> interval_"$i"_to_"$(( $i+10000 ))"
done

将间隔设置为 100 进行测试:

more inter*
::::::::::::::
interval_61336212_to_61346212
::::::::::::::
chr19   61336212        +       0       0       CG      CGT    
chr19   61336213        -       0       0       CG      CGG    
chr19   61336218        +       0       0       CG      CGG    
chr19   61336219        -       0       0       CG      CGC    
chr19   61336268        +       0       0       CG      CGG    
chr19   61336269        -       0       0       CG      CGA    
::::::::::::::
interval_61336312_to_61346312
::::::::::::::
chr19   61336402        +       0       0       CG      CGG    
chr19   61336403        -       0       0       CG      CGT  

注意:将为空间隔生成空文件;要删除空文件,请添加:

for file in interval* ; do
  if [ ! -s "$file" ] ; then
    rm "$file"
  fi
done

将为循环中的每个步骤运行文件for,因此不是最有效的。

答案4

如果您的意思只是计算而不是行计数:

awk 'NR==1 || n+10000<$2{n=$2; portion++}{print > FILENAME "." portion}' file

相关内容