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    

このファイルを2番目のフィールドの10000間隔(行ではなく数値間隔)ごとに分割したいと思います。したがって、このファイルの場合は、最初の行(61336212を含む行)から最大61346211(61336212 + 9999)を含む行に分割し、61346212から61356211まで分割したいと思います。ご覧のとおり、2番目のフィールド/列の数字は「塗りつぶされていません」です。

これを行う方法はありますか?

答え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

ファイルの書き込みを停止するとすぐにファイルを閉じます。そうしないと、何百ものファイルの後に同時に開くファイル数の制限に達します(GNUはawkこの制限を解決できますが、パフォーマンスは急速に低下します)。

我々はこの数が常に増加すると仮定します。

答え2

1行のバージョンをクラックします。たぶんもっと適しているかもしれませんコードゴルフしかし、このフォーラムより。これにより、分割1、分割2、分割3などのファイル名が生成されます。

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

出力ファイル名を分割001、分割002、分割003にするには追加の作業が必要です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

関連情報