パイプで区切られた2つのファイルがあり、列1 +列2が両方のファイルで一致する可能性があります。あるいは、あるファイルには項目が含まれ、別のファイルには項目が含まれていない可能性があります。 $1"-"$2 と同じ一致キーを FS として取得するために '|'パイプを使用すると仮定します。
ファイル1
1111|AAA|foo|50
1111|BBB|foo|30
2222|BBB|foo|10
ファイル2
1111|AAA|bar|10
1111|CCC|bar|20
3333|AAA|bar|40
最初の項目に必要な出力は次のとおりです(これがあります)。
1111|AAA|50|10
2番目の項目file1の場合(両方のファイルに一致するcolumn1 + column2がない場合は、fooの欠落項目を0に置き換えます。逆も同様です)
1111|BBB|30|0
ファイル 2 にはあるがファイル 1 にはない項目キー (列 1 + 列 2) の場合 (これは、ファイル 2 の項目 3 に対する期待される出力です。)
3333|AAA|0|40
したがって、目的の出力の完全な形式は、両方のファイルでcolumn1 + column2として表示されるすべての一意のキーを一覧表示することです。 3番目の列項目はファイル1の列4の値(ファイル1に値がない場合は0)、出力の4番目の列はファイル2の列4の値(値がファイル1にない場合)です。ファイル2値の場合は0))です。
研究もたくさん試していろいろ試してみましたが、次のコマンドを使ってみると、file2にはcolumn1+column2ペアがあり、file1にないと私の値は出力されません。
join -t"|" -e0 -a1 -a2 -o 1.2,1.3,1.5,2.5 <(<file1 awk -F"|" '{print $1"-"$2"|"$0}' | sort -k1,1) <(<file2 awk -F"|" '{print $1"-"$2"|"$0}' | sort -k1,1)
file1にはcolumn1 + column2の一致がありますが、file2にはない場合、上記の場合は予想される出力を提供し、存在しない一致に0を追加します...すべてのシナリオで動作させるにはどうすればよいですか?
上記のコマンドは、2つのファイルの列1(column1 + column2)にキーを追加し、新しいキーに基づいて結合していくつかの手続き型置換を実行します。 -e0 キーが file1 にあるが file2 にない場合は 0 が追加されます。新しいキー(column1-column2)がファイル2にはあるがファイル1にはない場合を処理するにはどうすればよいですか?
答え1
あなたの方法を使用すると、join
2回(またはjoin
1回の呼び出しで方法を変更してください。):
- 共通ラインとペアリングできない
file1
ライン印刷join -t'|' -e0 -a1 -o 1.2,1.3,1.5,2.5 <(<file1 awk -F'|' '{print $1"-"$2"|"$0}' | sort -t'|' -k1,1) <(<file2 awk -F'|' '{print $1"-"$2"|"$0}' | sort -t'|' -k1,1)
file2
ペアリングできないライン印刷join -t'|' -e0 -v2 -o 2.2,2.3,1.5,2.5 <(<file1 awk -F'|' '{print $1"-"$2"|"$0}' | sort -t'|' -k1,1) <(<file2 awk -F'|' '{print $1"-"$2"|"$0}' | sort -t'|' -k1,1)
awk
単一の呼び出しで同じ操作を実行できます。$4
たとえば、 で索引付けされた 2 つの配列に保存して$1|$2
から、END
ブロック内の各配列索引を繰り返し比較し、それに応じて印刷できます。
awk -F'|' 'NR==FNR{z[$1"|"$2]=$4;next}{x[$1"|"$2]=$4}
END{for (j in x){if (!(j in z)){print j, "0", x[j]}};
for (i in z){if (i in x){print i, z[i], x[i]} else {print i, z[i], "0"}}
}' OFS="|" file1 file2
答え2
次の|
2つのファイルの最初のファイルを@
(ファイルの他の場所に表示されない文字で)に置き換えて実行したjoin
後、@
元の元の|
。このようにして、|
元のファイルの列1と2を含む新しい区切り結合フィールドを作成します。
join -t'|' -e0 -a1 -a2 -o0,1.3,2.3 \
<( sed 's/|/@/' file1 | sort ) \
<( sed 's/|/@/' file2 | sort ) |
tr '@' '|'
出力フィールドの仕様(-o
)では、0は結合フィールドを表し、2つのファイルの列3は実際には元のデータの列4です。
与えられた入力ファイルに対して以下を生成します。
1111|AAA|50|10
1111|BBB|30|0
1111|CCC|0|20
2222|BBB|10|0
3333|AAA|0|40
答え3
別のawk
方法:
awk -F'|' 'NR==FNR{f1[$1FS$2]=$NF;next} {f2[$1FS$2]=$NF}
END{for (x in f1){print x,f1[x],f2[x]?f2[x]:0; delete f2[x]};
for (y in f2) print y, 0, f2[y]
}' file[12] OFS='|'
説明する:
NR==FNR{f1[$1FS$2]=$NF;next}
$1FS$2
、これはfile1に対してのみ実行され、キーの組み合わせを使用すると、名前付き配列に最後の列値が格納されます(awkに置き換えられます)。$NF
f1
FS
|
F生産するSオペレーター)。{f2[$1FS$2]=$NF}
、上記と同じですが、file2に対してのみ実行されます。for (x in f1){print x,f1[x],f2[x]?f2[x]:0; delete f2[x]}
、配列を繰り返し、f1
キー(x
)、file1の対応する値を印刷f1[x]
します。同じfile1キーがfile2に存在する場合はそれを印刷し、そうでない場合は0
(三項条件を使用してf2[x]?f2[x]:0
)印刷し、file2でも印刷します。同じレコードを削除します。キーdelete f2[x]
。for (y in f2) print y, 0, f2[y]
現在、配列f2
にはfile2にのみ存在するレコードが含まれているため、対応するキー(y
)0
はfile1に存在せず、その値はfile2に存在するため印刷しますf2[y]
。