"while" 루프에 "awk"를 중첩하여 두 파일을 한 줄씩 구문 분석하고 열 값을 비교합니다.

"while" 루프에 "awk"를 중첩하여 두 파일을 한 줄씩 구문 분석하고 열 값을 비교합니다.

awk일부 & 루프 조합에 대한 도움이 필요합니다 while. 열이 있는 두 개의 간단한 파일(일반 파일은 매우 큼)이 있습니다. 하나는 ID=10(코딩 영역(엑손), 여기서는 염색체 10)의 간단한 간격을 나타냅니다.

#exons.bed
10  60005   60100   
10  61007   61130   
10  61200   61300   
10  61500   61650   
10  61680   61850   

또 다른 하나는 순차적으로 읽고(=간격이 있지만 더 작음) 다른 값을 마지막 열로 사용하는 것을 의미합니다. 이는 나중에 필요합니다.

#reads.bed
10  60005   60010    34 
10  61010   61020    40
10  61030   61040    22
10  61065   61070    35 
10  61100   61105    41

그래서 빠르고 효율적인 방법으로 검색하여 어떤 읽기 간격(파일의 어떤 줄)과 인코딩 영역에 속하는 읽기 간격이 몇 개인지 알아내고 싶습니다.

exon 1(first interval of table 1) contains reads of line 1,2,3, etc. 
of   reads.file(2nd table)

이렇게 하면 나중에 각 엑손에 대한 이 행의 네 번째 열 값을 얻을 수 있습니다.

각 awk에 대해 읽기 행을 하나씩 구문 분석할 수 없기 때문에 while 루프에 대한 일부 수정이 필요할 수 있는 코드 조각을 작성했습니다. 여기있어:

while read chr a b cov; do  #for the 4-column file

#if <a..b> interval of read falls inside exon interval:
awk '($2<=$a && $b <= $3) {print NR}' exons.bed >> out_lines.bed

done < reads.bed

현재 a,b를 수동으로 제공할 때 awk 라인을 실행할 수 있지만 자동으로 실행되기를 원합니다.각 쌍 a, b에 대해파일을 통해.

구문 변경이나 변경 방법에 대한 제안을 주시면 감사하겠습니다!

후속 조치

마지막으로 다음 코드로 문제를 해결했습니다.

    awk 'NR==FNR{
        a[NR]=$2; 
        b[NR]=$3;
        next; }
    {  #second file
    s[i]=0; m[i]=0;  k[i]=0;              # Add sum and mean calculation
    for (i in a){                                            
       if($2>=a[i] && $3<=b[i]){         # 2,3: cols of second file here
          k[i]+=1
          print k                      #Count nb of reads found in
          out[i]=out[i]" "FNR          # keep Nb of Line of read 
          rc[i]=rc[i]" "FNR"|"$4       #keep Line and cov value of $4th col
          s[i]= s[i]+$4                #sum over coverages for each exon
          m[i]= s[i]/k[i]             #Calculate mean (k will be the No or  
                                       #reads found on i-th exon)
     }}  
    }
    END{
       for (i in out){
          print "Exon", i,": Reads with their COV:",rc[i],\
          "Sum=",s[i],"Mean=",m[i] >> "MeanCalc.txt"

    }}' exons.bed  reads.bed

산출:

   Exon 2 : Reads with their COV:  2|40 3|22 4|35 5|41 Sum= 138  Mean= 34.5
   etc.

답변1

awk첫 번째 문제는 그런 식으로 내부적으로 bash 변수를 사용할 수 없다는 것입니다 . $a내부 awk평가는대지 a그러나 는 a에 정의되어 있지 않기 때문에 비어 있습니다 . 이 문제를 해결하는 한 가지 방법은 의 옵션을 사용하여 변수를 정의하는 것 입니다.awkbashawk-v

-v var=val
--assign var=val
   Assign the value val to the variable var,  before  execution  of
   the  program  begins.  Such variable values are available to the
   BEGIN rule of an AWK program.

따라서 다음과 같이 할 수 있습니다.

while read chr a b cov; do 
  awk -v a="$a" -v b="$b" '($2<=a && b <= $3) {print NR}' exons.bed > out$a$b 
done < reads.bed

하지만 또 다른 오류가 있습니다. 읽기가 엑손 내에 속하기 위해서는 읽기의 시작 위치가 엑손의 시작 위치보다 커야 하고 끝 위치가 엑손의 끝 위치보다 작아야 합니다. 이를 사용하여 $2<=a && b <= $3엑손 경계 외부에서 시작하는 읽기를 선택합니다. 당신이 원하는 것은 입니다 $2>=a && $3<=b.

어쨌든, bash 루프에서 이러한 작업을 실행하는 것은 각 sum 쌍에 대해 a입력 파일을 한 번 읽어야 하기 때문에 매우 비효율적입니다 b. 왜 다 하지 않나요 awk?

awk 'NR==FNR{a[NR]=$2;b[NR]=$3; next} {
        for (i in a){
           if($2>=a[i] && $3<=b[i]){
            out[i]=out[i]" "FNR 
        }}}
        END{for (i in out){
                   print "Exon",i,"contains reads of line(s)"out[i],\
                   "of reads file" 
        }}' exons.bed reads.bed

위 스크립트를 샘플 파일에서 실행하면 다음과 같은 출력이 생성됩니다.

Exon 1 contains reads of line(s) 1 of reads file
Exon 2 contains reads of line(s) 2 3 4 5 of reads file

명확성을 위해 여기에는 덜 축약된 형태로 동일한 내용이 있습니다.

#!/usr/bin/awk -f

## While we're reading the 1st file, exons.bed
NR==FNR{
    ## Save the start position in array a and the end 
    ## in array b. The keys of the arrays are the line numbers.
    a[NR]=$2;
    b[NR]=$3; 
    ## Move to the next line, without continuing
    ## the script.
    next;
}
 ## Once we move on to the 2nd file, reads.bed
 {
     ## For each set of start and end positions
     for (i in a){
         ## If the current line's 2nd field is greater than
         ## this start position and smaller than this end position,
         ## add this line number (FNR is the current file's line number)
         ## to the list of reads for the current value of i. 
         if($2>=a[i] && $3<=b[i]){
             out[i]=out[i]" "FNR 
         }
     }
 }
 ## After both files have been processed
 END{
     ## For each exon in the out array
     for (i in out){
         ## Print the exon name and the redas it contains
         print "Exon",i,"contains reads of line(s)"out[i],
             "of reads file" 
        }

답변2

나는 그렇지 않다는 것을 안다.상당히무엇을 원하시나요? 하지만 개인적으로 저는 사교적인 사람이 아니므 awk로 Perl을 사용해 보는 것이 좋습니다.

이 같은:

#!/usr/bin/perl

#REALLY GOOD IDEA at the start of any perl code
use strict;
use warnings;

#open some files for input
open( my $exons, "<", 'exons.bed' ) or die $!;

#record where our exons start and finish. 
my %start_of;
my %end_of;

#read line by line our exons file. 
#extract the 3 fields and save 'start' and 'end' in a hash table. 
while (<$exons>) {
    my ( $something, $start, $end ) = split;

    my $exon_id = $.;    #line number;
    $start_of{$exon_id} = $start;
    $end_of{$exon_id}   = $end;
}
close ( $exons );

my %exons;
#run through 'reads' line by line, extracting the files. 

open( my $reads, "<", 'reads.bed' ) or die $!;
while (<$reads>) {
    my ( $thing, $read_start, $read_end, $value ) = split;

    #cycle through each exon. 
    foreach my $exon_id ( keys %start_of ) {

        #check if _this_ 'read' is within the start and end ranges. 
        if (    $read_start >= $start_of{$exon_id}
            and $read_end <= $end_of{$exon_id} )
        {
            #store the line number in our hash %exons. 
            push( @{ $exons{$exon_id} }, $. );
        }
    }
}
close ( $reads ); 

#cycle through %exons - in 'id' order. 
foreach my $exon_id ( sort keys %exons ) {
    #print any matches. 
    print "exon ",$exon_id, " (", $start_of{$exon_id}, " - ", $end_of{$exon_id},
        ") contains reads of line:", join( ",", @{ $exons{$exon_id} } ), "\n";
}

주어진 샘플 데이터를 고려하면:

exon 1 (60005 - 60100) contains reads of line:1
exon 2 (61007 - 61130) contains reads of line:2,3,4,5

좀 더 복잡한 범위 확인/검증을 쉽게 수행하려면 이를 확장할 수 있어야 합니다!

관련 정보