![awk/shell で同じレコードを持つ 2 つのファイルを行ごとにマージするにはどうすればよいですか?](https://rvso.com/image/168793/awk%2Fshell%20%E3%81%A7%E5%90%8C%E3%81%98%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%8C%81%E3%81%A4%202%20%E3%81%A4%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E8%A1%8C%E3%81%94%E3%81%A8%E3%81%AB%E3%83%9E%E3%83%BC%E3%82%B8%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E3%81%A9%E3%81%86%E3%81%99%E3%82%8C%E3%81%B0%E3%82%88%E3%81%84%E3%81%A7%E3%81%99%E3%81%8B%3F.png)
私は awk とシェルの初心者ですが、shell/awk を使用して同じレコードを持つ行を持つ 2 つのファイルをマージするにはどうしたらよいか知りたいです。file1 と file2 の名前の順序が異なる場合があります。同じレコードを持つ行のみをマージしたいです。助けてください。
file1.txt
Mary 68
Tom 50
Jason 45
Lu 66
file2.txt
Jason 37
Tom 26
Mary 74
Tina 80
mergefile.txt
Marry 68 74
Tom 50 26
Jason 45 37
awk を試してみましたが、スクリプトの実行に時間がかかります。もっと高速でシンプルな実装があるのではないかと考えています。
cat file1.txt | while read line
do
score1=$( echo $line | awk '{print $2}');
name1=$( echo $line | awk '{print $1}');
cat file2.txt | while read l
do
score2=$( echo $l | awk '{print $2}');
name2=$( echo $l | awk '{print $1}');
if [[ $name1 == $name2 ]]
then
echo "$name1 $score1 $score2" >> mergefile
break
fi
done
done
答え1
awk を使用する場合:
$ awk 'NR==FNR {a[$1] = $2; next} $1 in a {print $1, $2, a[$1]}' file2.txt file1.txt
Mary 68 74
Tom 50 26
Jason 45 37
ソートは不要で、出力は指定された 2 番目のファイルの順序になります。
説明:
NR==FNR
最初の名前のファイルからレコードを選択する標準的な方法です{a[$1] = $2; next}
最初のフィールドのキーと2番目のフィールドの値を配列に格納する$1 in a
最初のフィールドが最初のファイルに既に存在していた場合、{print $1, $2, a[$1]}
2番目のファイルからキーと値を出力し、1番目のファイルから値を出力します。
答え2
これは、join
、リレーショナルデータベース演算子
join <(sort file1.txt) <(sort file2.txt)
テスト
$ cat file1.txt
Mary 68
Tom 50
Jason 45
Lu 66
$ cat file2.txt
Jason 37
Tom 26
Mary 74
Tina 80
$ join <(sort file1.txt) <(sort file2.txt)
Jason 45 37
Mary 68 74
Tom 50 26
join
POSIX で規定された標準ツールです。
manjoin
ページには次のように記載されています:
The files file1 and file2 shall be ordered in the collating sequence of sort -b on the fields on which they shall be joined, by default the first in each line. All selected output shall be written in the same collating sequence.