若想合併兩個文字檔中基於共通欄位的資料,Linux 的 join 指令會是您的得力助手。它能讓您的靜態資料檔案動起來。接下來,我們將示範如何運用此指令。
跨檔案比對資料
數據至關重要。無論是公司、企業或家庭都仰賴數據運作。然而,若資料分散儲存在不同檔案,且由不同人員整理,那將會是一場惡夢。您不僅需要知道開啟哪些檔案才能找到所需資訊,檔案的版面配置和格式也可能大相逕庭。
您還必須處理檔案管理上的難題,例如哪些檔案需要更新、哪些需要備份、哪些是舊有檔案,以及哪些可以封存。
此外,若您需要整合資料或對整個資料集進行分析,還會面臨額外的挑戰。您該如何整理不同檔案中的數據,才能進一步進行處理?又該如何處理資料準備階段?
好消息是,如果這些檔案至少共享一個共通的資料元素,Linux 的 join 指令便能助您擺脫困境。
資料檔案
我們將使用虛構資料來示範 join 指令的用法,首先從以下兩個檔案開始:
cat file-1.txt
cat file-2.txt
以下是 file-1.txt 的內容:
1 Adore Varian [email protected] Female 192.57.150.231 2 Nancee Merrell [email protected] Female 22.198.121.181 3 Herta Friett [email protected] Female 33.167.32.89 4 Torie Venmore [email protected] Female 251.9.204.115 5 Deni Sealeaf [email protected] Female 210.53.81.212 6 Fidel Bezley [email protected] Male 72.173.218.75 7 Ulrikaumeko Standen [email protected] Female 4.204.0.237 8 Odell Jursch [email protected] Male 1.138.85.117
每行都包含一個編號,以及下列資訊:
一個號碼
一個名字
一個姓氏
電子郵件地址
性別
IP 位址
以下是 file-2.txt 的內容:
1 Varian [email protected] Female Western New York $535,304.73 2 Merrell [email protected] Female Finger Lakes $309,033.10 3 Friett [email protected] Female Southern Tier $461,664.44 4 Venmore [email protected] Female Central New York $175,818.02 5 Sealeaf [email protected] Female North Country $126,690.15 6 Bezley [email protected] Male Mohawk Valley $366,733.78 7 Standen [email protected] Female Capital District $674,634.93 8 Jursch [email protected] Male Hudson Valley $663,821.09
file-2.txt 中的每行包含以下資訊:
一個號碼
一個姓氏
電子郵件地址
性別
紐約的行政區
金額
join 指令搭配「欄位」使用,此處的欄位指的是以空格、行首或行尾區隔的文字段。若要根據共通欄位比對兩檔案中的行,則每一行都必須包含一個共通欄位。
因此,我們只能比對出現在兩個檔案中的欄位。IP 位址僅出現在一個檔案中,不適合。名字也僅出現在一個檔案中,因此也不能使用。姓氏同時出現在兩個檔案中,但這不是好選擇,因為不同的人可能會擁有相同的姓氏。
您也不能以性別欄位來比對資料,因為這太過模糊。紐約行政區和金額也僅出現在一個檔案中。
然而,我們可以利用電子郵件地址,因為它同時存在於兩個檔案中,且對每個人來說都是獨一無二的。快速瀏覽檔案可以確認兩個檔案中的行都對應於同一個人,因此我們也可以使用行號做為比對欄位(稍後我們將使用不同的欄位)。
請注意,這兩個檔案包含不同數量的欄位,這沒有問題——我們可以告知 join 指令使用哪個檔案的哪個欄位。
但是,請留意像紐約行政區這類欄位;在以空格分隔的檔案中,地區名稱中的每個詞都視為一個欄位。由於有些地區的名稱由兩個或三個詞組成,因此您實際上會在同一個檔案中看到不同數量的欄位。這沒關係,只要您比對紐約行政區之前的行中的欄位即可。
join 指令
首先,您想要比對的欄位必須排序。我們在這兩個檔案中都有遞增的數字,因此符合此標準。預設情況下,join 指令會使用檔案中的第一個欄位,這正是我們想要的。另一個合理的預設值是,join 指令預期欄位分隔符號為空格。再次強調,我們的情況符合此一條件,因此可以繼續執行 join 指令。
由於我們使用所有預設值,因此指令非常簡單:
join file-1.txt file-2.txt
join 指令會根據檔案在命令列中列出的順序將其視為「檔案一」和「檔案二」。
輸出如下:
1 Adore Varian [email protected] Female 192.57.150.231 Varian [email protected] Female Western New York $535,304.73 2 Nancee Merrell [email protected] Female 22.198.121.181 Merrell [email protected] Female Finger Lakes $309,033.10 3 Herta Friett [email protected] Female 33.167.32.89 Friett [email protected] Female Southern Tier $461,664.44 4 Torie Venmore [email protected] Female 251.9.204.115 Venmore [email protected] Female Central New York $175,818.02 5 Deni Sealeaf [email protected] Female 210.53.81.212 Sealeaf [email protected] Female North Country $126,690.15 6 Fidel Bezley [email protected] Male 72.173.218.75 Bezley [email protected] Male Mohawk Valley $366,733.78 7 Ulrikaumeko Standen [email protected] Female 4.204.0.237 Standen [email protected] Female Capital District $674,634.93 8 Odell Jursch [email protected] Male 1.138.85.117 Jursch [email protected] Male Hudson Valley $663,821.09
輸出格式如下:首先會印出比對行的欄位,然後是檔案一中其他的欄位,最後則是檔案二中未比對到的欄位。
未排序的欄位
讓我們嘗試一些我們已知無法成功的方法。我們會將這些行隨機排列到一個檔案中,因此 join 指令將無法正確處理此檔案。file-3.txt 的內容與 file-2.txt 相同,但第 8 行位於第 5 行和第 6 行之間。
以下是 file-3.txt 的內容:
1 Varian [email protected] Female Western New York $535,304.73 2 Merrell [email protected] Female Finger Lakes $309,033.10 3 Friett [email protected] Female Southern Tier $461,664.44 4 Venmore [email protected] Female Central New York $175,818.02 5 Sealeaf [email protected] Female North Country $126,690.15 8 Jursch [email protected] Male Hudson Valley $663,821.09 6 Bezley [email protected] Male Mohawk Valley $366,733.78 7 Standen [email protected] Female Capital District $674,634.93
我們輸入以下指令,嘗試將 file-3.txt 加入到 file-1.txt:
join file-1.txt file-3.txt
join 指令回報 file-3.txt 中的第七行有問題,因此未處理。第七行開頭的數字為 6,在正確排序的列表中,它應該在 8 之前。檔案中的第六行(開頭為「8 Odell」)是最後處理的行,因此我們可以看到它的輸出。
若要查看 join 指令是否對檔案的排序順序感到滿意,可以使用 –check-order 選項,它不會嘗試合併。
為此,我們輸入以下內容:
join --check-order file-1.txt file-3.txt
join 指令預先告知您檔案 file-3.txt 的第 7 行會有問題。
缺少行的檔案
在 file-4.txt 中,最後一行已移除,因此沒有第 8 行。內容如下:
1 Varian [email protected] Female Western New York $535,304.73 2 Merrell [email protected] Female Finger Lakes $309,033.10 3 Friett [email protected] Female Southern Tier $461,664.44 4 Venmore [email protected] Female Central New York $175,818.02 5 Sealeaf [email protected] Female North Country $126,690.15 6 Bezley [email protected] Male Mohawk Valley $366,733.78 7 Standen [email protected] Female Capital District $674,634.93
我們輸入以下內容,令人驚訝的是,join 指令不會抱怨,且會處理它可以處理的所有行:
join file-1.txt file-4.txt
輸出會列出七個合併的行。
-a (印出無法配對的項目) 選項會告知 join 指令也印出無法比對的行。
在此,我們輸入以下指令來告知 join 指令印出檔案 1 中無法與檔案 2 中的行比對的行:
join -a 1 file-1.txt file-4.txt
七行已配對,檔案一中的第八行會印出,且未配對。未顯示任何合併資訊,因為 file-4.txt 不包含可以配對的第 8 行。但是,至少它仍然會出現在輸出中,因此您知道它在 file-4.txt 中沒有配對項目。
我們輸入以下 -v(抑制串連行)指令來顯示任何未比對的行:
join -v file-1.txt file-4.txt
我們可以看到第八行是檔案二中唯一未配對的行。
比對其他欄位
讓我們在非預設欄位(欄位一)上比對兩個新檔案。以下是 file-7.txt 的內容:
[email protected] Female 192.57.150.231 [email protected] Female 210.53.81.212 [email protected] Male 72.173.218.75 [email protected] Female 33.167.32.89 [email protected] Female 22.198.121.181 [email protected] Male 1.138.85.117 [email protected] Female 251.9.204.115 [email protected] Female 4.204.0.237
以下是 file-8.txt 的內容:
Female [email protected] Western New York $535,304.73 Female [email protected] North Country $126,690.15 Male [email protected] Mohawk Valley $366,733.78 Female [email protected] Southern Tier $461,664.44 Female [email protected] Finger Lakes $309,033.10 Male [email protected] Hudson Valley $663,821.09 Female [email protected] Central New York $175,818.02 Female [email protected] Capital District $674,634.93
用於 join 指令的唯一合理欄位是電子郵件地址,它是第一個檔案中的第一個欄位,以及第二個檔案中的第二個欄位。為了符合此情況,我們可以利用 -1(檔案一的欄位)和 -2(檔案二的欄位)選項。我們會在這些選項後面加上一個數字,指示每個檔案中的哪個欄位應該用於連線。
我們輸入以下內容來告知 join 指令使用檔案一中的第一個欄位和檔案二中的第二個欄位:
join -1 1 -2 2 file-7.txt file-8.txt
這些檔案會根據電子郵件地址串連,而電子郵件地址會顯示為輸出中每一行的第一個欄位。
使用不同的欄位分隔符號
如果您的檔案的欄位並非以空格區隔,而是以其他符號分隔,該怎麼辦?
以下兩個檔案是以逗號分隔的,唯一的空格是位於多詞地名之間:
cat file-5.txt
cat file-6.txt
我們可以使用 -t(分隔符號)來告知 join 指令使用哪個字元做為欄位分隔符號。在此案例中,分隔符號是逗號,因此我們輸入以下指令:
join -t, file-5.txt file-6.txt
所有行都已配對,且空格會保留在地名中。
忽略字母大小寫
另一個檔案 file-9.txt 與 file-8.txt 幾乎相同。唯一的差異是,一些電子郵件地址包含一個大寫字母,如下所示:
Female [email protected] Western New York $535,304.73 Female [email protected] North Country $126,690.15 Male [email protected] Mohawk Valley $366,733.78 Female [email protected] Southern Tier $461,664.44 Female [email protected] Finger Lakes $309,033.10 Male [email protected] Hudson Valley $663,821.09 Female [email protected] Central New York $175,818.02 Female [email protected] Capital District $674,634.93
當我們將 file-7.txt 和 file-8.txt 加入時,運作良好。讓我們看看 file-7.txt 和 file-9.txt 會發生什麼。
我們輸入以下指令:
join -1 1 -2 2 file-7.txt file-9.txt
我們只配對了六行。大寫和小寫字母的差異阻止了其他兩個電子郵件地址的串連。
但是,我們可以利用 -i(忽略大小寫)選項強制連線忽略這些差異,並且比對包含相同文字的欄位,無論大小寫為何。
我們輸入以下指令:
join -1 1 -2 2 -i file-7.txt file-9.txt
所有八行都已比對,且成功串連。
串連起來
當您為了笨拙的資料準備工作而苦惱時,請使用 join 指令,它會是您強大的後盾。或許您需要分析資料,或者您正試圖將其轉換成特定格式,以便匯入至不同的系統。
無論情況為何,您都會很高興有 join 指令在您身邊!