こんにちは、よっしーです(^^)
今日は、joinコマンドをご紹介します。
join コマンドは、UNIXやLinuxシステム上で使用できるテキスト処理のコマンドの1つで、2つのファイルの共通行を結合して出力します(下図参照)。
先日、テキストファイルを結合する必要があり、joinコマンドを使用したので、そのときに使用したコマンドをシェアします。
joinコマンドとは
join
コマンドは、UNIXやLinuxシステム上で使用できるテキスト処理のコマンドの1つで、2つのファイルの共通行を結合して出力します。
そのため、join
コマンドを使うには、少なくとも2つのファイルが必要です。1つ目のファイルには共通のキーが含まれている必要があり、2つ目のファイルにも同じキーが含まれている必要があります。join
コマンドは、指定されたキーを使用して、2つのファイルを結合して、共通の行を出力します。
join
コマンドの基本構文は以下の通りです。
join [オプション] ファイル1 ファイル2
join
コマンドの一般的なオプションには以下があります。
-t
: フィールドの区切り文字を指定する。-1
: ファイル1の結合に使用するフィールドを指定する。-2
: ファイル2の結合に使用するフィールドを指定する。-a
: ファイル1もしくはファイル2で共通しない行も出力する。-o
: 出力するフィールドを指定する。- -e : 指定したフィールドがなければ任意の文字列を表示する。
- -v : ファイル1もしくはファイル2に共通しない行のみを出力する。
以下は、例として file1.txt
と file2.txt
を結合する方法です。
$ cat file1.txt
1 apple
2 orange
3 banana
$ cat file2.txt
1 red
2 orange
3 yellow
$ join file1.txt file2.txt
1 apple red
2 orange orange
3 banana yellow
-t オプション
joinコマンドの-tオプションは、フィールドの区切り文字を指定するために使用されます。
通常、joinコマンドは、複数のファイルに共通するフィールドを基準にして、それらを結合するために使用されます。デフォルトでは、フィールドはタブ文字によって区切られていることを前提としています。しかし、場合によっては、別の区切り文字を使用している場合もあります。この場合、-tオプションを使用して、適切な区切り文字を指定することができます。
たとえば、次のコマンドは、ファイルfile1.txtとfile2.txtをカンマで区切られたフィールドとして結合します。
% cat file1.txt
1,apple
2,orange
3,banana
% cat file2.txt
1,red
2,orange
3,yellow
% join -t, file1.txt file2.txt
1,apple,red
2,orange,orange
3,banana,yellow
-tオプション無しの場合だと、下記の結果になります。共通のキーはデフォルトの区切り文字が現れるまでの「2,orange」 となります。今回の場合は1行が共通キーとなります。そのため「2,orange」 のキーを持つ行が結合されて、下記のような出力結果にななります。
% join file1.txt file2.txt
2,orange
-1 オプション
-1 オプションは、ファイル1を結合する際に、使用するフィールドの列番号を指定します。
例えば、file1.txt の 2列目を共通キーとして使用すると下記のようになります。
% cat file1.txt
1 apple
2 orange
3 banana
% cat file2.txt
1 red
2 orange
3 yellow
% join -1 2 file1.txt file2.txt
# 出力なし
file1.txt の 2列目の値と、file2.txt の1列目の値で、共通の値を結合しようとしますが、共通の値がないため、出力結果としては、なしになります。
-2 オプション
-1 オプションと同様に、-2 オプションは、ファイル2を結合するときに使用するフィールドを指定します。
file2.txt の 2列目フィールドを共通キーとして使用した場合も出力なしとなります。
% cat file1.txt
1 apple
2 orange
3 banana
% cat file2.txt
1 red
2 orange
3 yellow
% join -2 2 file1.txt file2.txt
# 出力なし
file1.txt と file2.txt の 2つ目のフィールドを共通キーとして使用した場合は、orangeが結合されて出力されると予想できますが、結果は出力なしとなります。
% cat file1.txt
1 apple
2 orange
3 banana
% cat file2.txt
1 red
2 orange
3 yellow
% join -1 2 -2 2 file1.txt file2.txt
# 出力なし
これは、joinコマンドで結合する際は、共通キーがソートされている必要があるためです。今回の場合だと、2つ目のフィールドがソートされていないため、結合されませんでした。
下記のようにソートして、結合すると期待した結果になります。
% sort -k2,2 -o file1_sort.txt file1.txt
% cat file1_sort.txt
1 apple
3 banana
2 orange
% sort -k2,2 -o file2_sort.txt file2.txt
% cat file2_sort.txt
2 orange
1 red
3 yellow
% join -1 2 -2 2 file1_sort.txt file2_sort.txt
orange 2 2
-a オプション
join
コマンドの-a
オプションは、一方のファイルにしか存在しない行(ファイル1またはファイル2)も出力するように指定するオプションです。
-a
オプションには、以下の2つの引数を指定できます。
-a 1
: ファイル1にしか存在しない行も出力する-a 2
: ファイル2にしか存在しない行も出力する
また、-a
オプションは、join
コマンドを実行する前に、ファイルをソートする必要があります。ソートされていないファイルをjoin
コマンドに渡すと、正しい結果が得られない可能性があります。
以下は、-a 1
オプションを使用してjoin
コマンドを実行する例です。ファイル1にしか存在しない行(つまり、file1.txt
の4行目)も出力されます。
% cat file1.txt
1 apple
2 orange
3 banana
4 grape
% cat file2.txt
1 red
2 orange
3 yellow
5 black
% join -a 1 file1.txt file2.txt
1 apple red
2 orange orange
3 banana yellow
4 grape
同様に、-a 2
オプションを使用すると、ファイル2にしか存在しない行が出力されます。
% cat file1.txt
1 apple
2 orange
3 banana
4 grape
% cat file2.txt
1 red
2 orange
3 yellow
5 black
% join -a 2 file1.txt file2.txt
1 apple red
2 orange orange
3 banana yellow
5 black
また、-a 1 -a 2
オプションを使用すると、ファイル1もしくはファイル2にしか存在しない行が出力されます。
% cat file1.txt
1 apple
2 orange
3 banana
4 grape
% cat file2.txt
1 red
2 orange
3 yellow
5 black
% join -a 1 -a 2 file1.txt file2.txt
1 apple red
2 orange orange
3 banana yellow
4 grape
5 black
-o オプション
join
コマンドの-o
オプションは、出力するフィールドの形式を指定するために使用されます。
-o
オプションには、以下のような形式で指定します。
-o <オプション>
<オプション>
には、以下の値を指定できます。
- 0:結合に使用したフィールドを出力します。
1.1
:ファイル1の1列目のフィールドを出力します。1.2
:ファイル1の2列目のフィールドを出力します。2.1
:ファイル2の1列目のフィールドを出力します。2.2
:ファイル2の2列目のフィールドを出力します。2.1
:2番目のファイルの最初のフィールドを出力します。- その他の値:
-o
オプションで指定されたフィールドをカンマで区切って出力します。たとえば、-o 1.1,1.2,2.2
と指定すると、ファイル1の1列目と2列目のフィールド、およびファイル2の2列目のフィールドを出力します。
以下は、-o
オプションを使用してjoin
コマンドを実行する例です。ファイル1(file1.txt)は「ID」と「商品名」の2つのフィールドを持ち、ファイル2(file2.txt)は「ID」と「色」の2つのフィールドを持ちます。
% cat file1.txt
1 apple
2 orange
3 banana
4 grape
% cat file2.txt
1 red
2 orange
3 yellow
5 black
% join -o 1.2,2.2 file1.txt file2.txt
apple red
orange orange
banana yellow
この例では、-o 1.2,2.2
を使用して、ファイル1の2列目のフィールド(商品名)とファイル2の2列目のフィールド(色)を出力しています。
-e オプション
-e オプションは、指定したフィールドがなければ任意の文字列を表示する時に使用します。-o オプションと合わせて使用する必要があります。
% cat file1.txt
1 apple
2 orange
3 banana
4 grape
% cat file2.txt
1 red
2 orange
3 yellow
5 black
% join -a 1 -e xxx -o 1.2,2.2 file1.txt file2.txt
apple red
orange orange
banana yellow
grape xxx
-v オプション
join
コマンドの-v
オプションは、指定されたファイルに存在するが、結合先のファイルには存在しない行を抽出するために使用されます。
具体的には、-v
オプションには、1
または2
を指定することができます。-v 1
は、ファイル1に存在し、ファイル2には存在しない行を抽出し、-v 2
は、ファイル2に存在し、ファイル1には存在しない行を抽出します。
-v 1
オプションを使用してjoin
を実行すると、ファイル1に存在し、ファイル2には存在しない行(ここでは、4 grape
)が抽出されます。
% cat file1.txt
1 apple
2 orange
3 banana
4 grape
% cat file2.txt
1 red
2 orange
3 yellow
5 black
% join -v 1 file1.txt file2.txt
4 grape
同様に、-v 2
オプションを使用すると、ファイル2に存在し、ファイル1には存在しない行(ここでは、5 black)が抽出されます。
% cat file1.txt
1 apple
2 orange
3 banana
4 grape
% cat file2.txt
1 red
2 orange
3 yellow
5 black
% join -v 2 file1.txt file2.txt
5 black
応用
左外部結合
リレーショナル・データベースにおける LEFT OUTER JOIN をjoinコマンドで表現すると下記のようになります。
% cat file1.txt
1 apple
2 orange
3 banana
4 grape
% cat file2.txt
1 red
2 orange
3 yellow
5 black
% join -a 1 -e NULL -o 0,1.2,2.2 file1.txt file2.txt
1 apple red
2 orange orange
3 banana yellow
4 grape NULL
右外部結合
リレーショナル・データベースにおける RIGHT OUTER JOIN をjoinコマンドで表現すると下記のようになります。
% cat file1.txt
1 apple
2 orange
3 banana
4 grape
% cat file2.txt
1 red
2 orange
3 yellow
5 black
% join -a 2 -e NULL -o 0,1.2,2.2 file1.txt file2.txt
1 apple red
2 orange orange
3 banana yellow
5 NULL black
完全外部結合
リレーショナル・データベースにおける FULL OUTER JOIN をjoinコマンドで表現すると下記のようになります。
% cat file1.txt
1 apple
2 orange
3 banana
4 grape
% cat file2.txt
1 red
2 orange
3 yellow
5 black
% join -a 1 -a 2 -e NULL -o 0,1.2,2.2 file1.txt file2.txt
1 apple red
2 orange orange
3 banana yellow
4 grape NULL
5 NULL black
複数フィールドでの結合
複数フィールドを共通キーとしてjoinしたい場合は、複数フィールドを結合したフィールドを用意してjoin します。下記がその例になります。
% cat file1.txt
shopA 1 apple
shopB 1 apple
shopA 2 orange
shopB 2 orange
shopA 3 banana
shopB 4 grape
% awk '{print $1 "-" $2, $0}' file1.txt > file1_v2.txt
% sort -k1,1 -o file1_sort.txt file1_v2.txt
% cat file1_sort.txt
shopA-1 shopA 1 apple
shopA-2 shopA 2 orange
shopA-3 shopA 3 banana
shopB-1 shopB 1 apple
shopB-2 shopB 2 orange
shopB-4 shopB 4 grape
% cat file2.txt
shopA 1 red
shopB 1 red
shopA 2 orange
shopB 2 orange
shopA 3 yellow
shopA 5 black
% awk '{print $1 "-" $2, $0}' file2.txt > file2_v2.txt
% sort -k1,1 -o file2_sort.txt file2_v2.txt
% cat file2_sort.txt
shopA-1 shopA 1 red
shopA-2 shopA 2 orange
shopA-3 shopA 3 yellow
shopA-5 shopA 5 black
shopB-1 shopB 1 red
shopB-2 shopB 2 orange
% join file1_sort.txt file2_sort.txt
shopA-1 shopA 1 apple shopA 1 red
shopA-2 shopA 2 orange shopA 2 orange
shopA-3 shopA 3 banana shopA 3 yellow
shopB-1 shopB 1 apple shopB 1 red
shopB-2 shopB 2 orange shopB 2 orange
# -o オプションで出力するフィールドを指定すると見やすくなります
% join -o 0,1.4,2.4 file1_sort.txt file2_sort.txt
shopA-1 apple red
shopA-2 orange orange
shopA-3 banana yellow
shopB-1 apple red
shopB-2 orange orange
おわりに
今日は、joinコマンドについてご紹介しました。
いざというときに役に立ったりするので、頭の片隅にでもこんなコマンドがあったなと覚えておくといいと思います。その時は、このサイトを見返してもらえると嬉しいです。
またあしたお会いしましょう!!
コメント