National Taiwan University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

2

Local AI

--

Uedu Code

--

台灣大學 AQI 70 24°C PM2.5 17
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 12

資料串流指令

tr、cut、sort 與 uniq
Interaction 20 minute(s)

Learning Objectives

  • 用 tr 轉換大小寫、刪除字元(-d、-d -c),以及把連續重複的字元壓縮成一個(-s)
  • 用 cut 依分隔符號取出欄位(-d、-f),或依位置取出字元(-c)
  • 用 sort 排序,並用 -n、-r、-t、-k、-u 控制排序方式
  • 用 uniq 去除相鄰的重複行、用 -c 計算次數,並把這些指令串成管線統計出現次數排行

一個指令只做一件事

上一課學會了管線 |。這一課的四個指令都是「從標準輸入讀進一行一行的文字,處理後送到標準輸出」, 所以特別適合放在管線中間,像工廠的生產線一樣一站接一站處理資料:

指令 做的事 英文由來
tr 把字元換成別的字元,或刪掉某些字元 translate
cut 從每一行切出某幾個欄位或某幾個字元 cut
sort 把所有行排序 sort
uniq 把相鄰的重複行合併成一行 unique

每個指令都很單純,組合起來卻能完成「統計紀錄檔裡哪一種事件最多」這類工作。 Unix 的設計傳統就是讓每個程式只做好一件事,再用管線組合。

tr:轉換與刪除字元

tr [選項] 字元集1 [字元集2]

tr 只從標準輸入讀資料,後面不能直接接檔名;要處理檔案時寫成 tr … < 檔案 或 cat 檔案 | tr …。

寫法 作用
tr 'A-Z' 'a-z' 字元集1 的每個字元換成字元集2 對應位置的字元:大寫轉小寫
tr '[:upper:]' '[:lower:]' 同上,用字元類別表示;還有 [:digit:](數字)、[:space:](空白字元)
tr -d '0-9' 刪除(delete)字元集1 裡的字元
tr -d -c '0-9 \n' -c 取補集(complement):刪除「不是數字、空白、換行」的字元,等於只留下這些
tr -s ' ' 壓縮(squeeze):連續出現的同一個字元只留一個
tr -s '\n' ',' 先把換行換成逗號,再把連續的逗號壓縮成一個

投影片的例子:

$ echo "HELLO WORLD 123" | tr 'A-Z' 'a-z'
hello world 123
$ echo "HELLO WORLD 123" | tr -d '0-9'
HELLO WORLD
$ echo "@HELLO WORLD 123" | tr -d -c '0-9 \n'
  123

最後一個例子留下了兩個空白(原本在 HELLO 與 WORLD 後面)和 123。

\n 代表換行、\t 代表 Tab、\r 代表歸位字元。Windows 的文字檔每一行結尾是 \r\n 兩個字元, 投影片的 tr -s "\r\n" "," 就是用來處理從 Windows 複製過來的檔案;Linux 的文字檔只有 \n。

cut:切出欄位或字元

cut -d 分隔符號 -f 欄位 [檔案]     # 依欄位切
cut -c 字元位置 [檔案]             # 依字元位置切

-d(delimiter)指定欄位之間的分隔符號,不指定時預設是 Tab;-f(fields)指定要哪幾個欄位,從 1 開始編號:

寫法 取出
-f 2 第 2 欄
-f 1,5 第 1 欄與第 5 欄
-f 2-4 第 2 欄到第 4 欄
-f 3- 第 3 欄到最後
-f -3 第 1 欄到第 3 欄

-c(characters)的寫法相同,只是數的是字元位置,例如 -c 2-10 取每一行的第 2~10 個字元。

投影片的例子:

$ cut -d , -f 2 data.csv
3.2
3
3.2
3.1
7
$ ls -l /etc | tail -n 5 | cut -c 2-10
rwxr-xr-x
rw-r--r--
…

ls -l 每一行的第 1 個字元是檔案類型,第 2~10 個字元正好是權限。

/etc/passwd 每一行用冒號 : 分成 7 欄(帳號、密碼佔位、UID、GID、說明、家目錄、登入 shell), cut -d : -f 1,7 /etc/passwd 就能列出每個帳號用哪一個 shell。

欄位之間用「好幾個空白」對齊的輸出(例如 ls -l),用 cut -d ' ' 切會遇到空欄位,比較不好用; 這種情況改用 -c 依位置切,或第 15 課的 awk。

互動練習:用 tr 轉換字元、用 cut 切欄位

對應投影片的 Lab01、Lab02。按鈕都是真的指令;有 | 的指令執行後,右側會畫出管線每一段的輸出,看得到資料在每一站被改成什麼樣子。ip.txt 是每個 IP 後面跟著空行的清單,data.csv 是逗號分隔的資料。

sort 與 uniq:排序與去除重複

sort 預設把每一行當成字串,依字典順序由小到大排列:

選項 作用
-n 依數值大小排序(numeric);不加時 10 會排在 9 前面,因為是一個字一個字比
-r 反過來排(reverse),由大到小
-t 符號 指定欄位的分隔符號(預設是空白)
-k 2,2 只用第 2 欄當排序依據;寫 -k 2 是從第 2 欄一直到行尾
-u 排序後重複的行只留一行(unique)
-f 不分大小寫

投影片的 os.txt 依第 2 欄的數字排序:

$ sort -t , -k 2,2 -n os.txt
UbuntuOS,919
Window,1303
Apple,1677
Mac,2830

uniq 把相鄰的重複行合併成一行。它只會和上一行比較,所以重複的行如果分散在檔案各處,就去不乾淨; 先用 sort 讓相同的行排在一起,再交給 uniq,是最常見的用法。

寫法 作用
uniq 檔案 相鄰的重複行只留一行
uniq -c 每一行前面加上它連續出現的次數(count)
uniq -d 只列出有重複的行
uniq -u 只列出沒有重複的行

sort 檔案 | uniq 和 sort -u 檔案 的結果相同;要計算次數時就需要 uniq -c。

組合:統計出現次數排行

/var/log/dpkg.log 每一行的第 3 欄是 dpkg 做的動作(install、status、remove…)。想知道哪一種動作最多:

cut -d ' ' -f 3 /var/log/dpkg.log | sort | uniq -c | sort -nr | head -n 3
  1. cut 取出第 3 欄(以一個空白為分隔)
  2. sort 讓相同的動作排在一起
  3. uniq -c 計算每一種出現幾次
  4. sort -nr 依次數由大到小排
  5. head -n 3 只留前三名

把第 3 欄換成其他欄位或其他紀錄檔,就能統計「哪個 IP 連線最多」「哪個帳號登入最多次」這類問題。

互動練習:排序、去除重複與統計排行

對應投影片的 Lab03。os.txt 是「名稱,數字」的資料,dup.txt 有重複但不全部相鄰的句子。先比較只用 uniq 與「先 sort 再 uniq」的差別,最後一步一步加長管線,統計 /var/log/dpkg.log 裡哪一種動作最多;每加一段,右側的管線分段圖就多一格。

想一想:tr 與 cut

1.

echo "Hello 2026" | tr -d 'a-z' 會印出什麼?

2.

/etc/passwd 以冒號分隔欄位,第 1 欄是帳號、第 6 欄是家目錄。哪一個指令能列出這兩欄?

3.

echo "a b c" | tr -s ' ' 會印出什麼?

第 1 次作答

想一想:sort 與 uniq

1.

為什麼通常要先 sort 再 uniq?

2.

nums.txt 有三行:10、9、100。執行 sort nums.txt(不加 -n)的結果依序是?

3.

access.log 每一行的第 1 欄是連線的 IP(以空白分隔)。要列出連線次數由多到少的 IP,哪一條管線正確?

第 1 次作答

重點精華回顧

  • tr 只讀標準輸入:tr 'A-Z' 'a-z' 轉換、-d 刪除、-d -c 只留下指定的字元、-s 壓縮連續重複的字元。
  • cut -d 分隔符號 -f 欄位 切欄位(預設分隔符號是 Tab),cut -c 位置 切字元;欄位寫法有 2、1,5、2-4、3-。
  • sort 預設依字典順序;-n 數值、-r 反向、-t 分隔符號、-k 2,2 指定欄位、-u 去除重複。
  • uniq 只合併相鄰的重複行,所以先 sort;-c 計算次數、-d 只列重複的行。
  • cut … | sort | uniq -c | sort -nr | head 是統計出現次數排行的固定套路。
這一課完成了!
Next lesson:檔案搜尋
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。