awk를 사용하여 두 파일의 두 열을 비교하고 일치하지 않는 패턴을 인쇄하는 방법

awk를 사용하여 두 파일의 두 열을 비교하고 일치하지 않는 패턴을 인쇄하는 방법

데이터 파일이 있습니다 A.tsv(필드 구분 기호 = \t).

id  clade   mutation
243 40A siti,toto,mumu
254     
267 40B lala,sisi,sojo

및 템플릿 파일 B.tsv(필드 구분 기호 = \t):

40A toto,xixi,saxa
40B lala,sojo,huhu
40C sasa,sisi,lala

공통 clade를 기반으로 A.tsv템플릿의 돌연변이를 비교하고 싶습니다 B.tsv. 두 가지 질문이 있습니다.

  1. B.tsv"missing_mutation"이라는 새 열에 존재하지 않는 돌연변이의 이름을 어떻게 표시할 수 있습니까 A.tsv?
  2. A.tsv에 존재하지만 (문자로 시작 s, 대소문자를 구분하지 않음) 에는 존재하지 않는 돌연변이의 이름을 "remaining_mutation"이라는 새 열에 어떻게 표시할 수 있습니까 B.tsv?

C.tsv다음과 같습니다.

id  clade   mutation    missing_mutation    remaining_mutation
243 40A siti,toto,mumu  xixi,saxa   siti
254     
267 40B lala,sisi,sojo  huhu    sisi

다음과 같이 두 파일을 비교하는 방법을 알고 있습니다.

awk -F"," -vOFS="," '    
    NR==FNR {
     a[$2]=$3;
     next
    }
    
    { print $0,a[$2] }
' B.tsv A.tsv > C.tsv

하지만 일치하지 않는 항목을 인쇄하는 방법을 모르겠습니다. 좋은 아이디어가 있나요?

답변1

다음 awk프로그램은 편의를 위해 awk("진정한 이중 인덱스 배열"의 형태로) GNU를 사용하며 이 문제를 해결해야 합니다. 이는 두 파일을 인수로 사용하여 순차적으로 호출되도록 의도되었습니다 B.txt A.txt(코드 예제에서 수행하는 것과 마찬가지로).

#!/bin/awk -f

BEGIN{FS=OFS="\t"}

NR==FNR {
    n_tmp[$1]=split($2,buff,/,/)
    for (i=1;i<=n_tmp[$1];i++) mut_tmp[$1][i]=buff[i]
    next
}

FNR==1 {
    print $0,"missing_mutation","remaining_mutation"
}

FNR>1 {
    n_curr=split($3,mutations,/,/)
    mut_miss=0
    mut_rem=0

    # Find missing
    for (j=1;j<=n_tmp[$2];j++)
    {
        for (i=1;i<=n_curr;i++)
        {
            if (mutations[i]==mut_tmp[$2][j]) break
        }
        if (i>n_curr) mut_miss=mut_miss ? mut_miss "," mut_tmp[$2][j] : mut_tmp[$2][j]
    }

    # Find remaining
    for (i=1;i<=n_curr;i++)
    {
        for (j=1;j<=n_tmp[$2];j++)
        {
            if (mutations[i]==mut_tmp[$2][j]) break;
        }
        if (j>n_tmp[$2] && mutations[i]~/^[Ss]/) mut_rem=mut_rem ? mut_rem "," mutations[i] : mutations[i]
    }
    
    if (!mut_miss) mut_miss=""
    if (!mut_rem) mut_rem=""

    print $0,mut_miss,mut_rem
}
  • 그러면 먼저 clade nr에 대한 상관 테이블이 생성됩니다. 템플릿을 구문 분석할 때 이를 돌연변이 목록과 비교하세요 B.tsv. 여기서 템플릿 돌연변이 목록은 명시적으로 개별 돌연변이 배열로 분할됩니다. 편의상 mut_tmp첫 번째 인덱스가 분기 번호인 "이중 인덱스" 배열을 사용하고 있다는 점에 유의하세요 . 두 번째는 돌연변이의 색인 번호입니다. 돌연변이 개수도 배열에 저장됩니다 n_tmp.
  • 구문 분석할 때 A.tsv새 헤더를 먼저 인쇄합니다.
  • 그런 다음 각 행에 대해 먼저 필드 3의 변형 목록을 배열로 분할합니다 mutations.
  • 그런 다음 현재 클레이드( )에 대한 템플릿 돌연변이 목록의 각 항목을 mut_tmp[$2]기존 돌연변이( )와 mutations비교하여 "누락된 돌연변이" 필드를 채웁니다.
  • s다음으로, 현재 변이 목록의 각 항목을 현재 클레이드의 템플릿 변이와 비교하여 "나머지 변이" 필드를 채우고 변이가 또는 로 시작하는지 확인합니다 S.

GNU를 사용할 수 없다면 다음을 대체하여 awk대부분의 다른 구현과 함께 작동하도록 할 수 있습니다.awk

mut_tmp[a][b]

그리고

mut_tmp[a,b]

\034이는 계통 번호와 돌연변이 이름 에 기본적으로 개별 구성 요소를 단일 문자열 배열 인덱스에 연결하는 데 사용되는 특수 문자가 포함되어 있지 않은 것으로 나타나기 때문에 작동합니다 ( SUBSEP자세한 내용은 내부 변수를 찾으세요).

입력 예제의 출력은 다음과 같습니다.

~$ awk -f compare.awk B.tsv A.tsv 
id  clade   mutation    missing_mutation    remaining_mutation
243 40A siti,toto,mumu  xixi,saxa   siti
254             
267 40B lala,sisi,sojo  huhu    sisi

예제에서 요구하는 출력이 요구 사항 설명과 일치하지 않습니다.

편집하다

A.tsv실제로 분기군은 22열에 있고 돌연변이는 41열에 있다는 점을 귀하의 의견에서 지적하셨으므로 변경하시기 바랍니다.

  • split($3,mutations,/,/)도착하다split($41,mutations,/,/)
  • 모든 n_tmp[$2]발생n_tmp[$22]
  • mut_tmp[$2][j](또는 [$2,j])에서 mut_tmp[$22][j](또는 [$22,j]) 까지의 모든 항목

답변2

선택하다 awk:

awk 'BEGIN{ FS=OFS="\t" }
NR==FNR{ mutations[$1] =$2; next }

FNR>1  {
         split($3, muts, "," );
         for(x in muts) { 
             if (gsub( ",?"muts[x]",?", "", mutations[$2])>0) delete muts[x] }
       }

FNR==1 { $4="missing_mutation"; $5="remaining_mutation" }

{ printf ("%s", $0 OFS mutations[$2] OFS );
  for(r in muts) {
      if(muts[r] ~/^[Ss]/) printf("%s", sep muts[r]); sep="," }
  print ""; sep=""
}' fileB  fileA

관련 정보