join 指令:文字檔的 SQL-like 合併 文章首圖

join 指令:文字檔的 SQL-like 合併

join 指令:文字檔的 SQL-like 合併

在 Linux 系統管理與資料處理的日常工作中,我們經常需要將分散在不同檔案中的相關資訊整合在一起。雖然 awkgrep 是強大的工具,但它們通常需要撰寫較複雜的腳本邏輯。這時,join 指令就顯得格外親切且高效。

join 是一個非常實用的 Unix 指令,它能夠根據兩個檔案中的共同欄位(類似於 SQL 中的 JOIN 操作),將兩份純文字檔合併成一份。對於習慣使用關聯式資料庫的使用者來說,join 的邏輯幾乎是直觀的:只要兩邊都有相同的「鍵值(Key)」,就將對應的資料行拼接起來。

本文將深入解析 join 的用法,並透過實際範例展示如何在 Ubuntu 22.04 或 Debian 12 系統上高效完成資料合併任務。

基本語法與前提

join 的核心概念是「對齊」。在使用 join 之前,必須確保兩個檔案都是已排序(Sorted)的狀態,且排序依據必須與指定的連接欄位一致。這是新手最容易忽略的關鍵點。

基本語法如下:

join [選項] 檔案1 檔案2

預設情況下,join 會根據兩個檔案的第一個欄位進行合併。如果兩個檔案的第一欄位內容相同,它會將這兩行的其餘內容拼接起來。

實際操作範例

為了演示,我們建立兩個簡單的 CSV 風格檔案。假設我們有一個員工資料檔 employees.txt 和一個部門資料檔 departments.txt

步驟 1:準備測試資料

請在終端機執行以下指令建立測試檔案:

# 建立員工資料 (ID, Name)
cat > employees.txt <<EOF
1 Alice
2 Bob
3 Charlie
4 David
EOF

# 建立部門資料 (ID, Department)
cat > departments.txt <<EOF
1 Engineering
2 Marketing
3 Sales
5 HR
EOF

步驟 2:執行基本合併

我們希望找出每個員工所屬的部門。執行以下指令:

join employees.txt departments.txt

輸出結果:

1 Alice Engineering
2 Bob Marketing
3 Charlie Sales

解析:

  • 123 是兩個檔案共有的 ID,因此這三行被合併。
  • 4 David 沒有出現在 departments.txt 中,因此被遺漏。
  • 5 HR 沒有出現在 employees.txt 中,因此也被遺漏。
  • 預設情況下,join 會移除連接鍵(ID),並將剩餘欄位用空白字元連接。

進階應用:控制連接鍵與欄位顯示

預設行為雖然方便,但在實際工作中,我們通常需要更精確的控制。例如,我們可能希望保留 ID 欄位,或者根據非第一個欄位進行連接。

1. 指定連接欄位 (-1-2)

假設資料格式變更為 Name,IDDepartment,ID,此時 ID 位於第二欄。我們需要告訴 join 在哪一欄進行比對。

# 建立新的測試資料
cat > emp_new.txt <<EOF
Alice,1
Bob,2
Charlie,3
EOF

cat > dept_new.txt <<EOF
Engineering,1
Marketing,2
Sales,3
EOF

# 指定 emp_new.txt 的第 2 欄和 dept_new.txt 的第 2 欄作為連接鍵
join -1 2 -2 2 emp_new.txt dept_new.txt

輸出結果:

1,Alice,Engineering
2,Bob,Marketing
3,Charlie,Sales

注意:預設分隔符號是空白字元。如果檔案使用逗號 , 分隔,必須使用 -t 選項指定分隔符號。

2. 指定分隔符號 (-t)

join -1 2 -2 2 -t ',' emp_new.txt dept_new.txt

輸出結果:

1,Alice,Engineering
2,Bob,Marketing
3,Charlie,Sales

3. 顯示未匹配的列 (-a)

有時我們需要知道哪些資料「沒有」匹配成功。例如,找出沒有部門的員工。

# -a 1 表示顯示檔案1中未匹配的列
join -1 2 -2 2 -t ',' -a 1 emp_new.txt dept_new.txt

輸出結果:

1,Alice,Engineering
2,Bob,Marketing
3,Charlie,Sales
Bob,2

這顯示了所有匹配的資料,以及 emp_new.txt 中多出來的 Bob,2(假設這裡是模擬情境,實際上 Bob 已匹配,此處僅展示語法結構,若將 emp_new.txt 改為 Alice,1; Eve,4,則會顯示 Eve,4)。

常見問題與注意事項

1. 為什麼我的 join 輸出是空的?

這是最常見的問題。join 要求輸入檔案必須是字典序排序的。如果檔案未排序,join 無法正確比對,通常會產生空輸出或錯誤訊息。

解決方法: 在執行 join 之前,先對檔案進行排序:

sort employees.txt > employees_sorted.txt
sort departments.txt > departments_sorted.txt
join employees_sorted.txt departments_sorted.txt

或者使用流程控制(Process Substitution)直接在指令中排序:

join <(sort employees.txt) <(sort departments.txt)

2. 如何處理欄位中的特殊字元或空白?

預設情況下,join 以空白字元作為欄位分隔符。如果欄位內容包含空白(例如姓名為 "Van Dyke"),預設行為會將其視為多個欄位,導致比對失敗。

解決方法: 務必使用 -t 選項指定明確的分隔符號(如逗號 |:),並確保原始資料的分隔符號與 -t 指定的一致。避免在純文字檔中使用空白作為主要分隔符,除非你確定欄位內容不含空白。

小結

join 指令是 Linux 文字處理工具箱中一把被低估的利器。它提供了類似 SQL INNER JOIN 的功能,但速度更快、資源佔用更少,特別適合處理小型至中型的純文字檔。

掌握 join 的關鍵在於:

  1. 確保檔案已排序
  2. 正確指定連接欄位-1, -2)。
  3. 正確指定分隔符號-t)。

透過熟練運用這些選項,你可以輕鬆地在命令行中完成複雜的資料整合工作,無需依賴龐大的資料庫軟體。下次遇到需要合併兩個檔案的需求時,不妨先試試看 join 吧!