【Linux】joinコマンドの使い方|共通キーでファイルを横結合

【Linux】joinコマンドの使い方|共通キーでファイルを横結合

PR Amazonのアソシエイトとして、ITナレッジライフは適格販売により収入を得ています。

記事の文字数:4,793

Linuxのjoinコマンドを使って、共通するキー列(フィールド)を基準に2つのファイルを横方向に結合する方法を解説します。事前のsortが必要な理由や、外部結合(-a)、不一致行の抽出(-v)、CSVファイルの結合(-t)まで具体例付きで紹介します。

Linuxユーザにお勧めの本 ↗

最新版

ゼロからはじめるLinuxサーバー構築・運用ガイド 第2版 動かしながら学ぶWebサーバーの作り方

難易度
実用性
最新度

Rocky Linux対応。実際にWebサーバーを公開するまでのプロセスを体験できる、最も確実で実践的なガイドブックです。

初心者向け

わかばちゃんと学ぶ サーバー監視

難易度
実用性
読みやすさ

マンガと図解が中心で圧倒的に読みやすい。負荷調査の手法がスッと理解できるようになります。

新しいLinuxの教科書 第2版

難易度
実用性
読みやすさ

一生モノの基礎知識が身につく定番書です。

ゼロからわかる Linuxコマンド200本ノック―基礎知識と頻出コマンドを無理なく記憶に焼きつけよう!

難易度
実用性
習得度

アウトプット重視で記憶に定着しやすい。反復練習でLinux操作が自由自在になります。

エンジニア1年生のための世界一わかりやすいLinuxコマンドの教科書

難易度
実用性
読みやすさ

LinuxLinux [リナックス / ライナックス]オープンソースのOSカーネルで複数のテキストデータやCSVCSV [シーエスブイ]Comma-Separated Values。カンマ区切りのデータ形式ファイルを扱う際、「社員IDや商品コードをキーにして、2つのファイルをデータベースのJOINのように結合したい」「片方のファイルにしか存在しないデータ(不一致行)だけを抽出したい」といった場面はよくあります。

この記事では、2つのファイルに共通するフィールド(列)を基準として行を横方向に結合する join コマンドの使い方を解説します。基本的な内部結合の動作から、-a や -v オプションによる外部結合・不一致抽出、CSVファイルの結合、そして実行時によく遭遇する「is not in sorted order」エラーの対処法までを具体例とともに紹介します。

この記事を読むことで、join コマンドの仕様や事前ソートのルールを正しく理解し、コマンドライン上でリレーショナルなデータ結合や突合処理を簡潔に実行できるようになります。

確認した環境

本記事で解説するコマンドや出力結果は、以下の環境で実機検証を行っています(バージョン確認コマンド: join --version)。

OSOS [オーエス]Operating System。基本ソフトウェアGNU coreutils バージョン
DebianDebian [デビアン]コミュニティ主導で開発される安定性の高いLinuxディストリビューション GNU/Linux 11 (bullseye)GNU coreutils 8.32(join (GNU coreutils) 8.32)
UbuntuUbuntu [ウブントゥ]人気のLinuxディストリビューション 24.04 LTSGNU coreutils 9.4(join (GNU coreutils) 9.4)
AlmaLinux 9.4GNU coreutils 8.32(join (GNU coreutils) 8.32)

Linuxのjoinコマンドとは?共通キーでファイルを結合する基本機能

join コマンドは、2つのテキストファイルから「共通するキー項目(フィールド)」を持つ行を探し出し、1行にまとめて標準出力へ書き出すコマンドです。SQLSQL [エスキューエル / シークエル]Structured Query Language。関係データベース(RDB)の管理や操作を行うデータベース言語における JOIN 句に近い感覚で、テキストデータ同士の突き合わせ(マージ)を行えます。

paste・cat・awkコマンドとの違いと使い分け

Linuxで複数のファイルを結合・加工するコマンドには paste や cat、awk などもあります。それぞれの役割と join との違いは以下の通りです。

コマンド結合の仕組み・特徴主な用途
join共通するキー列の値を照合して2つのファイルを横方向に結合する(事前のソートが必要)IDやホスト名をキーにしたマスタ結合、2ファイル間の突合・差分抽出
pasteキーの照合は行わず、同じ行番号同士をそのまま横方向に結合する行順が完全に揃っている別ファイルの単純連結、縦並びデータの1行化
cat複数のファイルを縦方向(行単位)にそのまま連結する分割されたログファイルやテキストの縦方向の結合
awk連想配列などを用いて任意の条件でデータを照合・抽出・加工するソート順を変えずに結合したい場合や、複雑な条件分岐・集計を伴う処理

単純に1行目同士・2行目同士を横に並べたい場合はpasteコマンド、特定の列だけを切り出したい場合はawkコマンドやcutコマンドを使用します。一方、欠番や行数の違いがある2つのデータを「IDが一致する行同士」で簡潔に結び付けたい場合は join コマンドが適しています。

基本構文と主なオプション一覧

join コマンドの基本構文は以下の通りです。

Terminal window
join [オプション] <ファイル1> <ファイル2>

<ファイル1> または <ファイル2> に -(ハイフン)を指定した場合は、標準入力からデータを読み取ります。また、オプションで指定しない限り、デフォルトでは各ファイルの1列目(第1フィールド)が結合キーとして扱われ、空白文字(スペースまたはタブ)が区切り文字となります。

join コマンドでよく使用する主なオプションは以下の通りです。

オプション役割
オプションなし両方のファイルでキーが一致した行のみを出力する(SQLの内部結合 INNER JOIN に相当)
-1 <列番号><ファイル1> の結合キーとして使用する列番号を指定する(デフォルトは 1)
-2 <列番号><ファイル2> の結合キーとして使用する列番号を指定する(デフォルトは 1)
-t <文字>入出力のフィールド区切り文字を <文字> に変更する(CSVなら -t ',')
-a <ファイル番号>キーが一致しない行も含めて出力する(1 または 2 を指定。外部結合 OUTER JOIN に相当)
-v <ファイル番号>キーが一致しなかった行のみを出力する(1 または 2 を指定)
-e <文字列>外部結合時にデータが存在しない空フィールドを <文字列> で埋める(-o と併用)
-o <書式>出力する列の順番や項目を指定する(例: 1.1,2.2 または auto)
--header各ファイルの1行目をヘッダー行として扱い、ソート順のチェックを行わずに先頭へ結合出力する
-i(--ignore-case)キーの比較時にアルファベットの大文字・小文字の違いを無視する

【基本】2つのファイルを内部結合・外部結合する方法

まずはサンプルファイルを作成し、キーが一致する行の結合(内部結合)や、一致しない行も含める結合(外部結合)の基本動作を確認します。

以下のように、社員IDと名前が記録された users.txt と、社員IDと部署名が記録された depts.txt を用意します。どちらのファイルも第1フィールド(社員ID)の昇順で並んでいます。

Terminal window
$ cat << 'EOF' > users.txt
001 alice
002 bob
003 charlie
EOF
$ cat << 'EOF' > depts.txt
001 sales
002 dev
004 hr
EOF

デフォルト動作:両方のファイルに存在するキーのみ結合(内部結合)

オプションを付けずに join users.txt depts.txt を実行すると、両方のファイルの1列目に共通して存在する 001 と 002 の行だけが結合されて出力されます。

Terminal window
$ join users.txt depts.txt
001 alice sales
002 bob dev

出力される列の順番は、デフォルトで「結合キー → ファイル1の残りの列 → ファイル2の残りの列」となります。片方にしか存在しない 003(users.txt のみ)と 004(depts.txt のみ)は出力されません。

-aオプション:一致しない行も残して出力する(外部結合)

SQLの左外部結合(LEFT OUTER JOIN)や完全外部結合(FULL OUTER JOIN)のように、相手側のファイルにキーが存在しない行も出力結果に残したい場合は、-a オプションにファイル番号(1 または 2)を指定します。

Terminal window
# ファイル1(users.txt)の不一致行(003)も残す(左外部結合に相当)
$ join -a 1 users.txt depts.txt
001 alice sales
002 bob dev
003 charlie
# 両方のファイルの不一致行(003 と 004)をすべて残す(完全外部結合に相当)
$ join -a 1 -a 2 users.txt depts.txt
001 alice sales
002 bob dev
003 charlie
004 hr

-eと-o auto:欠損値(空欄)を特定の文字列で埋める

上の join -a 1 -a 2 の出力を見ると、003 charlie や 004 hr のようにフィールド数が2つしかなく、どちらのファイルの列が欠けているのか判別しにくい状態になっています。

欠損しているフィールドに NONE や NULL などの代替文字列を入れて列数を揃えたい場合は、-e <文字列> オプションと -o auto オプションを組み合わせて実行します。

Terminal window
$ join -a 1 -a 2 -e "NONE" -o auto users.txt depts.txt
001 alice sales
002 bob dev
003 charlie NONE
004 NONE hr

-o auto を指定することで、各ファイルの1行目の列数をもとに全体の出力フォーマットが自動決定され、欠損箇所(003 の部署名や 004 の名前)が NONE で埋められて3列に揃います。-e オプションは単独では機能せず、-o(auto または列指定)と併用する必要がある点に注意してください。

-vオプション:一致しなかった行(差分)だけを抽出する

結合結果ではなく、「ファイル1にあるがファイル2にはない行」のようにキーが一致しなかった行だけを取り出したい場合は、-v オプションにファイル番号(1 または 2)を指定します。

Terminal window
# ファイル1(users.txt)にしか存在しないキーの行を抽出する
$ join -v 1 users.txt depts.txt
003 charlie
# ファイル2(depts.txt)にしか存在しないキーの行を抽出する
$ join -v 2 users.txt depts.txt
004 hr

マスタデータとトランザクションデータの突合チェックにおいて、「未登録のIDが含まれていないか」を洗い出す用途で重宝します。

【実践】結合キーの列指定・出力列の並び替え・CSVファイルの結合

実務のデータでは「結合キーが1列目ではない」「カンマ区切りのCSVでヘッダー行が付いている」といったケースが多くあります。それぞれの対応方法を確認します。

-1・-2・-oオプション:2列目以降をキーにして出力列を指定する

結合キーが1列目以外にある場合は、-1 <列番号> でファイル1のキー列、-2 <列番号> でファイル2のキー列を指定します。

ただし重要な前提として、各ファイルは「結合キーとして指定する列」の順番で事前にソートされている必要があります。以下の例では、emp.txt の2列目(部署コード)と dept_master.txt の1列目(部署コード)をキーにして結合します。

Terminal window
$ cat << 'EOF' > emp.txt
alice 101
bob 102
charlie 101
EOF
$ cat << 'EOF' > dept_master.txt
101 Sales
102 Development
EOF
# emp.txt を結合キーである2列目(-k 2,2)で事前にソートする
$ sort -k 2,2 emp.txt > emp_sorted.txt
# ファイル1の2列目(-1 2)とファイル2の1列目(-2 1)で結合する
$ join -1 2 -2 1 emp_sorted.txt dept_master.txt
101 alice Sales
101 charlie Sales
102 bob Development

emp_sorted.txt には部署コード 101 を持つ行が2行(alice と charlie)存在しますが、join コマンドは1対多(または多対多)のキーに対しても自動的にそれぞれの行へマスタ側の値(Sales)を結合して出力します。

このとき、「先頭に部署コード(結合キー)が出力されるのを変えて、名前・部署名・部署コードの順に並べたい」という場合は、-o オプションで <ファイル番号>.<列番号>(結合キー自体は 0)をカンマ区切りまたは空白区切りで指定します。

Terminal window
# ファイル1の1列目(1.1)、ファイル2の2列目(2.2)、結合キー(0)の順に出力する
$ join -1 2 -2 1 -o 1.1,2.2,0 emp_sorted.txt dept_master.txt
alice Sales 101
charlie Sales 101
bob Development 102

不要な列を除外して結合したい場合も、同様に -o オプションを使うことで後からcutコマンドを実行せずに1コマンドで整形できます。

-tと—header:ヘッダー付きのCSVファイルを結合する

カンマ(,)区切りのCSVファイルを結合する場合は、-t ',' で区切り文字を指定します。さらに1行目にカラム名(ヘッダー)が含まれている場合は、--header オプションを付けることで、1行目をソート対象外の見出しとして扱い、結果の先頭に結合して出力できます。

Terminal window
$ cat << 'EOF' > users.csv
id,name,role
001,alice,admin
002,bob,editor
003,charlie,viewer
EOF
$ cat << 'EOF' > scores.csv
id,score
001,95
002,82
004,70
EOF
# カンマ区切り(-t ',')かつ1行目をヘッダー(--header)として結合する
$ join -t ',' --header users.csv scores.csv
id,name,role,score
001,alice,admin,95
002,bob,editor,82

タブ(\t)区切りのTSVファイルを結合したい場合は、BashのANSI-Cクォーテーションを使って join -t $'\t' file1.tsv file2.tsv と記述します。

「is not in sorted order」エラーの原因とsort連携の注意点

join コマンドを使用する際にもっともつまずきやすいのが、事前のソート順に関するエラーです。原因と確実な対処法を確認しておきましょう。

エラーが発生する原因(事前ソートが必須である理由)

join コマンドは、2つのファイルを先頭から順番に読み進めながらキーを比較するアルゴリズムを採用しています。そのため、両方のファイルが結合キーの文字列順(辞書順)で昇順ソートされていないと、正しく一致判定ができずエラーで停止します。

Terminal window
$ cat << 'EOF' > unsorted1.txt
002 bob
001 alice
EOF
$ cat << 'EOF' > unsorted2.txt
001 sales
002 dev
EOF
# キーが昇順に並んでいないためエラーになり、001 alice が結合されない
$ join unsorted1.txt unsorted2.txt
join: unsorted1.txt:2: is not sorted: 001 alice
002 bob dev
join: input is not in sorted order

プロセス置換 <(...) と sort コマンドで一時ファイルを作らずに結合する

未ソートのファイルを結合する場合、わざわざソート済みの一時ファイルを作成しなくても、Bashのプロセス置換 <(command) とsortコマンドを組み合わせることで1行のコマンドで安全に結合できます。

Terminal window
# 両ファイルを1列目(-k 1,1)でソートしながらそのまま join に渡す
$ join <(LC_ALL=C sort -k 1,1 unsorted1.txt) <(LC_ALL=C sort -k 1,1 unsorted2.txt)
001 alice sales
002 bob dev

ここで実務上の重要なポイントが2つあります。

  1. sort には -n(数値ソート)を付けない: join コマンドはキーを数値ではなく**文字列(辞書順)**として比較します。sort -n で数値順に並べると(例: 2 の後に 10 が来る)、辞書順(10 の後に 2 が来る)を期待する join 側でソート順エラーになります。
  2. LC_ALL=C と -k <列>,<列> を明示する: 環境のロケール設定による並び順のズレを防ぐため、LC_ALL=C を付けてバイト値順に統一し、sort -k 1,1 のように結合キーの列のみをソート基準に指定すると確実です(CSVの場合は LC_ALL=C sort -t ',' -k 1,1)。
  3. --nocheck-order でエラーを隠さない: join にはソート順のチェックを無効化する --nocheck-order オプションがありますが、これを指定してもエラー表示が消えるだけで、未ソートの行(先ほどの例では 001 alice)は結合されずに欠落します。必ず事前に sort を行ってください。

まとめ:joinコマンドでキーを基準にしたファイル結合を効率化しよう

本記事では、Linuxの join コマンドによる共通キーを基準としたファイル結合の方法と、実務での注意点を解説しました。

記事の要点を以下にまとめます。

  • join コマンドは、2つのファイルの共通キー(デフォルトは1列目)を照合して横方向に内部結合する。
  • -a オプションで一致しない行も含めた外部結合ができ、-v オプションを使えば片方のファイルにしか存在しない不一致行だけを抽出できる。
  • CSVファイルを結合する際は -t ',' を指定し、1行目が見出しの場合は --header を併用する。
  • 入力ファイルは事前に結合キーの**辞書順(文字列順)**でソートされている必要があり、join <(LC_ALL=C sort -k 1,1 file1) <(LC_ALL=C sort -k 1,1 file2) のようにプロセス置換を使うと一時ファイルなしで安全に結合できる。

行番号順の単純結合を行う paste コマンドや、ほかのテキスト検索・加工コマンドとの組み合わせについては、Linuxのテキスト処理・検索コマンドの使い方まとめもあわせて参考にしてください。


以上で本記事の解説を終わります。
よいITライフを!
ITナレッジライフ 運営者
この記事を書いた人

Z (ITナレッジライフ)

現役のITエンジニア。Linux、プログラミング、IT用語など、日々の業務で得た「痒いところに手が届く」技術情報を発信しています。

プロフィールと編集ポリシーを見る →

Linuxユーザにお勧めの本 ↗

最新版

ゼロからはじめるLinuxサーバー構築・運用ガイド 第2版 動かしながら学ぶWebサーバーの作り方

難易度
実用性
最新度

Rocky Linux対応。実際にWebサーバーを公開するまでのプロセスを体験できる、最も確実で実践的なガイドブックです。

人気記事


記事を評価

Thanks!
目次
Scroll to Top