Unix와 Awk를 사용하여 두 파일 비교

Unix와 Awk를 사용하여 두 파일 비교

4개의 필드(파일 1의 필드 1, 2, 4, 5와 파일 2의 필드 1, 2, 4, 5)를 사용하여 두 파일 File1과 File2(공백으로 구분)를 비교해야 합니다.

논리:
파일 1의 열 1, 2, 4가 파일 2의 열 1, 2, 4와 일치하고 열 5가 일치하지 않으면 파일 1과 파일 2의 두 줄이 연결되어 출력으로 리디렉션됩니다. 따라서 출력 파일에는 File1과 File2의 열 1, 2, 4가 일치하지만 열 5는 일치하지 않는 행만 포함됩니다.

파일 1:

sc2/80         20      .        A       T         86       PASS     N=2     F=5;U=4
sc2/60         55      .        G       T         76       PASS     N=2     F=5;U=4 
sc2/68         20      .        T       C         71       PASS     N=2     F=5;U=4
sc2/24         24      .        T       G         31       PASS     N=2     F=5;U=4

파일 2:

sc2/80         20      .        A        C        80      PASS    N=2       F=5;U=4
sc2/60         55      .        G        C        72      PASS    N=2       F=5;U=4 
sc2/68         20      .        T        C        71      PASS    N=2       F=5;U=4 
sc2/10         24      .        T        G        31      PASS    N=2       F=5;U=4
sc2/40         59      .        T        G        31      PASS    N=2       F=5;U=4
sc2/24         24      .        A        G        38      PASS    N=2       F=5;U=4

산출:

sc2/80         20      .        A       T        86      PASS     N=2      F=5;U=4
sc2/80         20      .        A       C        80      PASS     N=2      F=5;U=4

sc2/60         55      .        G       T        76      PASS     N=2      F=5;U=4 
sc2/60         55      .        G       C        72      PASS     N=2      F=5;U=4

저는 이 분야를 처음 접했고 도움을 주셔서 감사합니다.

답변1

당신은 그것을 사용할 수 있습니다 awk. 스크립트에 다음을 입력하세요 script.awk.

FNR == NR {
  f1[$1,$2,$4] = $0
  f1_c14[$1,$2,$4] = 1
  f1_c5[$1,$2,$4] = $5
  next
}  

f1_c14[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print f1[$1,$2,$4];
}

f1[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print $0;
}

이제 다음과 같이 실행하세요.

$ awk -f script.awk file1  file2
sc2/80         20      .        A       T         86       PASS     N=2     F=5;U=4
sc2/80         20      .        A        C        80      PASS    N=2       F=5;U=4
sc2/60         55      .        G       T         76       PASS     N=2     F=5;U=4 
sc2/60         55      .        G        C        72      PASS    N=2       F=5;U=4

스크립트는 다음과 같이 작동합니다. 이 블록은 , 및 3개의 배열을 f1생성 f1_c14합니다 f1_c5. f1file1의 열 1, 2, 4의 내용을 사용하여 인덱싱된 배열에 있는 file1의 모든 행을 포함합니다. f1_c14은 동일한 인덱스(1, 2, 4의 내용)와 값을 가진 또 다른 배열입니다 1. 세 번째 배열은 처음 2개와 동일한 인덱스를 사용하며 해당 값은 file1의 열 5 값입니다.

FNR == NR {
  f1[$1,$2,$4] = $0
  f1_c14[$1,$2,$4] = 1
  f1_c5[$1,$2,$4] = $5
  next
} 

다음 블록은 file1열 1, 2, 4가 의 열과 일치하는 경우 첫 번째 파일의 행을 인쇄하는 역할을 담당합니다 file2.그리고AND의 5번째 열이 일치하지 않으면 file1해당 행만 인쇄됩니다.file1file2

f1_c14[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print f1[$1,$2,$4];
}

세 번째 블록은 열 1, 2, 4에 해당하는 배열의 관련 행을 인쇄하는 역할을 합니다. 다시 말하지만, 열 5가 일치하지 않는 경우에만 인쇄됩니다 file2.f1file2

f1[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print $0;
}

위의 스크립트를 다음과 같이 실행하세요.

$ awk -f script.awk file1  file2
sc2/80         20      .        A       T         86       PASS     N=2     F=5;U=4
sc2/80         20      .        A        C        80      PASS    N=2       F=5;U=4
sc2/60         55      .        G       T         76       PASS     N=2     F=5;U=4 
sc2/60         55      .        G        C        72      PASS    N=2       F=5;U=4 

column다음을 사용하여 출력을 약간 정리할 수 있습니다 .

$ awk -f script.awk file1  file2 | column -t
sc2/80  20  .  A  T  86  PASS  N=2  F=5;U=4
sc2/80  20  .  A  C  80  PASS  N=2  F=5;U=4
sc2/60  55  .  G  T  76  PASS  N=2  F=5;U=4
sc2/60  55  .  G  C  72  PASS  N=2  F=5;U=4

어떻게 작동하나요?

FNR == NR

awk이는 특정 방식으로 파일을 반복하는 기능을 활용합니다 . 여기에서는 파일을 반복하고 있으며 첫 번째 파일의 한 줄에 있을 때 file해당 줄의 특정 코드 블록을 실행하려고 합니다 file1.

이 예는 FNR == NR2개의 시뮬레이션 파일을 제공할 때 수행되는 작업을 보여줍니다. 그 중 하나에는 4개의 행이 있고 다른 하나에는 5개의 행이 있습니다.

$ awk 'BEGIN {print "NR\tFNR\tline"} {print NR"\t"FNR"\t"$0}' \
     <(seq 1 4) <(seq 1 5)
NR  FNR line
1   1   1
2   2   2
3   3   3
4   4   4
5   1   1
6   2   2
7   3   3
8   4   4
9   5   5
기타 블록

다른 블록 f1_c14[$1,$2,$4]AND는 f1[$1,$2,$4]해당 배열 요소의 값에 값이 있는 경우에만 실행됩니다.

답변2

이것이 Perl의 솔루션입니다. 다음 코드를 파일에 저장하고 스크립트로 실행해야 합니다(아래 참조).

#!/usr/bin/perl
$file1 = '/path/to/file1';
$file2 = '/path/to/file2';
open $f1,'<',$file1;
open $f2,'<',$file2;
while(<$f1>){
    ($c1,$c2,$c4,$c5) = (split / /)[0,1,3,4]; #get relevant columns in file 1
    $lines_dictionary{"$c1 $c2 $c4"}="$c5---$_"; #create a hash entry keyed by the relevant columns
}
while(<$f2>){
    ($c1,$c2,$c4,$c5) = (split / /)[0,1,3,4]; #get relevant columns in file 2
    if(exists $lines_dictionary{"$c1 $c2 $c4"}){ #if a line with similar columns was seen in file 1
        ($file1_c5,$file1_line) = split /---/,$lines_dictionary{"$c1 $c2 $c4"}; #parse the hash entry this line in file 1
        if($file1_c5 -ne $c5){ #if column 5 of file 2 doesn't match column 5 of file 1
            print "${file1_line}$_\n"; #we only need one extra newline as the lines read from the files have trailing ones.
        }
    }
}
close $f1;
close $f2;

텍스트 편집기를 사용하여 이 스크립트를 파일에 붙여넣고 $file1$file2변수를 수정하여 파일의 실제 위치를 반영한 ​​후 다음을 수행하여 스크립트를 실행 가능하게 만듭니다.

$ chmod +x /path/to/script

마지막으로 스크립트를 호출합니다.

$ /path/to/script

부인 성명

  • 이 코드는 테스트되지 않았습니다.
  • 이 코드에서는 "---" 패턴이 열 5에 나타날 가능성이 없다고 가정합니다.
  • 이 코드는 파일 1의 행이 고유하다고 가정합니다(즉, 각 행에 "column1, column2, column4"의 서로 다른 조합이 있음). 관련 열에 동일한 데이터를 포함하는 여러 행(연속적이지 않아도 됨)이 있는 경우 스크립트는 해당 행의 마지막 행(파일의 맨 아래 행)을 사용합니다.

관련 정보