次のように比較的小さなスペースで区切られたファイルがあります(ただし、多くの列と行があります)。
ファイル1:
Entry1
a
b
c
d
次のように、1行に多くの重複項目がある別の巨大なタブ区切りファイルです。
ファイル2:
value ID1 ID2
1 a aaaa1
1 a aaaa2
1 b bbbb1
1 b bbbb2
1 b bbbb3
1 d aaaa4
まず、以下のように、file1の各項目とfile2のID1フィールド(列2)の間の一致を指定して、file1と同じサイズのタブで区切られたファイルを印刷しようとします。これは別の質問です。:
Entry1
a
b
NoMatch
d
また、file1とfile2の値を含むマージタブで区切られたファイルを印刷します。今回はfile2に重複した項目がありますが、次のようにNoMatchも保持します。
value ID1 ID2
1 a aaaa1
1 a aaaa2
1 b bbbb1
1 b bbbb2
1 b bbbb3
NoMatch NoMatch NoMatch
1 d aaaa4
Joinコマンドを使用しようとすると、NoMatchメッセージが表示されます。
join -a1 -e "NoMatch" <(awk -F ' ' '{print $0}' file1.txt |tail -n +2|sort -k1,1) <(cat file2 | sort -k1,1) > out.txt
しかし、これはfile1のすべての内容を印刷するので何か間違っているようです。ただし、file2に一致するものがない場合、残りのフィールドは空です(したがって、「NoMatch」というメッセージは表示されません)。私がどんな人なのかを理解するのに役立ちますか?何か間違っていましたか?
とても感謝しています!
#
Gilesさん、ありがとうございます。今すぐ参加したので、あなたの意見に答えることができないようです...あなたの提案は次のとおりです。
join -a1 -e "NoMatch" -11 -22 --header -o2.1,2.2,2.3 file1 file2
2番目のクエリOutput2を修正しました。ありがとうございます! file1と同じ行を持つ最初のOutput1を取得する方法を尋ねてください。もう一度ありがとうございます! !
don_crisstiの助けを借りて、次の2番目の出力を得ることができます。
paste -d'\t' file2 <(awk 'FNR==NR{seen[$1]++; next} {(FNR==1 || ($1 in seen)) || $1="NoMatch"};1' file2 file1)
答え1
読みやすくするために、元の例の形式を再指定します。
join -a1 -e "NoMatch" \
<(awk -F ' ' '{print $0}' file1.txt |tail -n +2|sort -k1,1) \
<(cat file2 | sort -k1,1)
すべての問題はjoin
file2の処理とオプションに関連しています。
- file2は、フィールド1(フィールド2でなければならない)に基づいてソートされます。
-t '<tab>'
options がない場合、join
file2 はタブで区切られます。join
file2フィールド2を結合するオプションがありません。- file2のフィールドが正しい場合でも、デフォルトの
join
出力はリンクされたフィールドを最初に印刷するため、オプションを指定する-o FORMAT
必要がありますjoin
。 - file2 ヘッダーは削除されません。
- 問題は発生しませんが、処理は不要です。最初の行をスキップできるため、
tail
file1には必要ありません。awk
-F ' '
オプションは必要ありませんawk
。
これらの問題を修正すると、次の結果が得られます。
#!/bin/bash
head -1 file2
join -t ' ' -2 2 -a 1 -e NoMatch -o 2.1,2.2,2.3 \
<(awk 'NR==1{next} {print $0}' file1.txt | sort) \
<(tail -n +2 file2 | sort -k2)
これにより、タブで区切られた次の出力が生成されます。
value ID1 ID2
1 a aaaa1
1 a aaaa2
1 b bbbb1
1 b bbbb2
1 b bbbb3
NoMatch NoMatch NoMatch
1 d aaaa4