sort 與 uniq:資料排序與去重的實踐 文章首圖

sort 與 uniq:資料排序與去重的實踐

sort 與 uniq:資料排序與去重的實踐

在 Linux 系統管理與資料處理的日常工作中,我們經常需要面對雜亂無章的文字資料。無論是分析伺服器日誌、整理用戶清單,還是清洗 CSV 數據,排序(Sorting)去重(Deduplication)都是最基礎且頻繁的操作。雖然現代有 Python、AWK 甚至 SQL 等強大的工具,但在快速檢查資料或進行管道(Pipeline)處理時,sortuniq 這對黃金組合依然不可取代。

這篇文章將深入解析這兩個指令的核心用法,並透過實際範例,帶你掌握高效處理文字資料的技巧。

核心指令解析:sort

sort 指令負責將輸入的資料行進行排序。預設情況下,它會依據 ASCII 碼值進行升序排列。然而,透過各種選項,我們可以輕鬆應對數字、日期或特定欄位的複雜排序需求。

基礎排序與數字排序

當我們處理包含數字的資料時,預設的字串排序會導致錯誤的結果(例如 10 會排在 2 前面)。此時,必須使用 -n 選項強制進行數值排序。

# 建立測試檔案
echo -e "10\n2\n1\n20" > numbers.txt

# 預設字串排序(錯誤的結果)
sort numbers.txt
# 輸出:1, 10, 2, 20

# 正確的數值排序
sort -n numbers.txt
# 輸出:1, 2, 10, 20

多條件排序

實務上,我們常需要「先依條件 A 排序,若 A 相同則依條件 B 排序」。這可以透過 -k 選項指定欄位(Field)來達成。假設我們有一個學生成績清單,格式為 姓名 國文 英文

echo -e "Alice 85 90\nBob 90 85\nAlice 90 85\nCharlie 85 90" > grades.txt

# 先依國文成績(第2欄)降序排列,若國文相同,再依英文成績(第3欄)降序排列
sort -t ' ' -k2,2nr -k3,3nr grades.txt

這裡 -t ' ' 指定空白鍵為欄位分隔符號,-k2,2nr 表示從第 2 欄到第 2 欄,以數值(n)且反向(r)排序。

核心指令解析:uniq

uniq 指令的作用非常單純:移除相鄰的重複行。注意關鍵在於「相鄰」。如果重複的資料被其他資料隔開,uniq 是無法將其合併的。因此,uniq 幾乎總是搭配 sort 使用。

基本去重與計數

echo -e "apple\nbanana\napple\ncherry\nbanana\napple" > fruits.txt

# 基本去重(需先排序)
sort fruits.txt | uniq
# 輸出:apple, banana, cherry

# 顯示每行出現的次數
sort fruits.txt | uniq -c
# 輸出:
#       3 apple
#       2 banana
#       1 cherry

-c 選項非常實用,它能讓我們快速掌握資料的分佈情況。

找出重複或唯一的行

除了統計次數,我們有時需要明確知道哪些是重複的,或哪些是唯一的。

# 僅顯示重複出現的行(會顯示所有重複項,包含第一次出現的)
sort fruits.txt | uniq -d
# 輸出:
# apple
# banana

# 僅顯示出現過一次的行
sort fruits.txt | uniq -u
# 輸出:
# cherry

實戰應用:日誌分析與資料清洗

讓我們結合 sortuniq 來解決一個常見問題:找出伺服器日誌中出現頻率最高的 IP 地址。假設我們有一個名為 access.log 的檔案,其中包含多行 HTTP 請求記錄。

# 假設 IP 位於每行的開頭
# 192.168.1.1 GET /index.html
# 10.0.0.5 POST /api/data
# 192.168.1.1 GET /login

# 步驟 1: 提取 IP (使用 awk)
# 步驟 2: 排序
# 步驟 3: 去重並計數
# 步驟 4: 依計數數值降序排列,並顯示前 10 名
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -10

這一行指令是 Linux 系統管理員的必備技能,它能瞬間揭示潛在的 DDoS 攻擊來源或最熱門的訪問端。

常見問題與注意事項

1. 為什麼 uniq 沒有去除重複資料?

這是新手最常遇到的陷阱。uniq 只會移除相鄰且完全相同的行。如果資料未經排序,重複的項目可能分散在檔案的不同位置。

解決方案: 務必在 uniq 前加上 sort

# 錯誤示範
echo -e "B\nA\nB" | uniq
# 輸出:B, A, B (重複的 B 未被移除)

# 正確示範
echo -e "B\nA\nB" | sort | uniq
# 輸出:A, B

2. 排序結果與預期不符(大小寫問題)

預設的 sort 是基於 ASCII 碼排序,這意味著大寫字母會排在小寫字母之前(例如 Z 會排在 a 前面)。若希望進行不區分大小寫的字典序排序,可以使用 -f(fold)選項。

echo -e "apple\nBanana\ncherry" | sort
# 輸出:Banana, apple, cherry (B < a)

echo -e "apple\nBanana\ncherry" | sort -f
# 輸出:apple, Banana, cherry (忽略大小寫)

小結

sortuniq 雖然看似簡單,但它們是 Linux 文字處理管道中不可或缺的基石。透過熟練運用 -n-k-c 等選項,並理解其底層邏輯(特別是 uniq 依賴相鄰性),你可以輕鬆處理從簡單的清單整理到複雜的日誌分析等多種任務。在 Ubuntu 22.04 與 Debian 12 等現代發行版中,這些指令的效能與相容性皆表現優異,值得每一位 Linux 使用者深入掌握。