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


8

我有一个如下文件:

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,依此类推。如您所见,第二个字段/列中的数字未“填充”。

有没有办法做到这一点?


在您的示例中,如果在61346211之后的下一个数字是61346220,例如,您是否希望输出的第二个文件覆盖从61346212或61346220开始的范围?
Joe Lee-Moyet 2015年

第二范围应覆盖从61346212.
agathusia

Answers:


13
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.0000file.0001...(数量是int(($2-n)/10000)其中n$2第一个行)。

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

我们假设这些数字一直在上升。


3
你能解释发生了什么吗?
Fiximan

你能解释一下发生了什么吗?就像下面的注释一样,输出文件名长度也必须保持不变,例如file.0000,file.0001而不是file.1 file.2 .. file.100 .. file..2320?
agathusia

1
@Fiximan,我觉得如果不解释代码就无法解释更多。您觉得哪一部分不清楚?
斯特凡Chazelas

好吧,我了解文件名的生成file = ...,但是迭代如何工作?没有一部分说n = n + 10000也没有lower_boundary <= $2 < upper_boundary一部分。总的来说,整个if (file != last_file) { close(last_file) ; last_file = file }比赛超出了我的范围
Fiximan

1
@Fixman,是的,这就是我所说的if (file != last_file):如果当前文件与前一个文件不同,请关闭前一个文件(因此一次只能打开一个文件(我们不需要保留它们)所有其他解决方案都一样开放))
StéphaneChazelas 15年

7

破解一线版。也许比此论坛更适合Code Golf。这将生成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éphaneChazelas确定的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

1
对于此方法,是否有一种方法可以使文件名连续多个。这将输出split1 .... split100 ... split1000,但是在split00001 ... split 00100 .. split01000 ..行中还有更多内容。
agathusia

1
当然,sprintf现在添加了额外的魔法。
史蒂夫2015年

请注意,如果输入具有0、9999、12000、19999、21000、22000,则将0、9999放入file1,但将12000、19999、21000放入file2,这似乎与要求不符。
斯特凡Chazelas

1
请注意,这将在几百个文件之后达到同时打开文件数的限制(GNU awk可以解决该限制,但是性能会迅速下降)。
斯特凡Chazelas

1
是的 我刚刚注意到您提到的问题。
agathusia 2015年

4
#!/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循环中的每个步骤运行文件,因此效率不是最高。


3

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

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

请注意,如果输入具有0、9999、12000、19999、21000、22000,则将0、9999放入file1,但将12000、19999、21000放入file2,这似乎与要求不符。
斯特凡Chazelas

请注意,这将在几百个文件之后达到同时打开文件数的限制(GNU awk可以解决该限制,但是性能会迅速下降)。
斯特凡Chazelas

@StéphaneChazelas我不确定不清楚您的理解。如果您想在第3个文件中使用21000,请使用9999而不是10000。–
Costas

根据我对问题的理解,OP希望在第一个文件中包含0到9999,在第二个文件中包含10000到19999的行。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.