UnixとAwkを使用した2つのファイルの比較

UnixとAwkを使用した2つのファイルの比較

4つのフィールド(ファイル1のフィールド1、2、4、5とファイル2のフィールド1、2、4、5)を使用して、2つのファイルFile1とFile2(スペースで区切り)を比較する必要があります。

論理:
ファイル 1 の列 1、2、4 がファイル 2 の列 1、2、4 と一致し、列 5 が一致しない場合、ファイル 1 とファイル 2 の 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_c5f1file1の列1、2、4の内容を使用して索引付けされた配列内のfile1のすべての行を含みます。f1_c14は、同じインデックス(1、2、4の内容)と値を持つ別の配列です1。 3番目の配列は最初の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];
}

3番目のブロックは、列1、2、4に対応する配列の関連行を印刷する役割を果たします。繰り返しますが、列5が一致しない場合にのみ印刷されますfile2f1file2

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これは特定の方法でファイルを繰り返す機能を利用します。ここではファイルを繰り返し、最初のファイルの1行にあるときにfileその行の特定のコードブロックを実行しようとしていますfile1

この例は、FNR == NR2つのシミュレーションファイルを提供するときに実行されるアクションを示しています。そのうちの1つには4つの行があり、もう1つには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」の異なる組み合わせがあります)。関連列に同じデータを含む複数の行(連続する必要はありません)がある場合、スクリプトはその行の最後の行(ファイルの一番下の行)を使用します。

関連情報