awk 是資料處理瑞士刀,內建函數涵蓋算術運算、字串操作、正則替換,並支援使用者自訂函數。本文分類整理所有常用函數,附帶參數說明、回傳值與實戰範例。
| 函數 | 說明 | 範例 |
|---|---|---|
int(x) | 向下取整 | int(4.9)=4, int(-4.1)=-5 |
rand() | 0 ≤ r < 1 偽隨機數 | rand() → 0.237788 |
srand([x]) | 設定隨機種子,回傳舊種子 | srand() 用當前時間 |
# 錯誤:未呼叫 srand(),每次執行產生相同序列
BEGIN { print rand(); print rand() }
# 正確:BEGIN 區塊呼叫 srand()
BEGIN { srand(); print rand(); print rand() }
srand() 無參數時以當前時間(秒)為種子,確保每次執行序列不同。
| 函數 | 說明 | 備註 |
|---|---|---|
gsub(r, s, [t]) | 全域替換 t 中匹配 r 為 s,回傳替換次數 | t 預設 $0 |
sub(r, s, [t]) | 僅替換首次匹配,成功回傳 1 | t 預設 $0 |
index(s, t) | 回傳 t 在 s 中位置(1-based),無則 0 | |
length([s]) | 字串長度,預設 $0 | |
match(s, r) | 正則 r 在 s 中首次匹配位置,設定 RSTART/RLENGTH | |
split(s, a, [sep]) | 依 sep 分割 s 存入陣列 a,回傳元素數,預設 FS | |
sprintf(fmt, ...) | 格式化字串,回傳而非列印 | |
substr(s, p, [n]) | 子串:位置 p 起長度 n,省略 n 至尾 | |
tolower(s) | 轉小寫,回傳新串 | 原串不變 |
toupper(s) | 轉大寫,回傳新串 | 原串不變 |
# 資料:Jelly:26:12474125874:04713365412:0081245:Jelly
gsub(/Jelly/, "JellyThink") # 全域替換
# → JellyThink:26:...:JellyThink
sub(/JellyThink/, "Jelly") # 僅首次
# → Jelly:26:...:JellyThink
n = split($0, field, ":")
for (i=1; i<=n; ++i) {
printf "[%d]=%-12s, 長度:%d\n", i, field[i], length(field[i])
}
function name(param1, param2, ...) {
# 區域變數需在參數列宣告(慣例用額外參數模擬)
statements
return value
}
# 錯誤示範:函數內變數洩漏為全域
function insert(str, pos, ins) {
before = substr(str, 1, pos)
after = substr(str, pos+1)
return before ins after
}
{ print insert($0, 5, "JellyThink") }
# 執行後 before、after 殘留全域,污染主程式
# 正確:在參數列宣告區域變數
function insert(str, pos, ins, before, after) {
before = substr(str, 1, pos)
after = substr(str, pos+1)
return before ins after
}
{ print insert($0, 5, "JellyThink") }
# before、after 為區域,外部不可見
鐵律:awk 函數參數**傳值**,函數內變數預設**全域**,必須在參數列以額外參數佔位模擬區域變數。
# 處理 CSV:欄位去空白、大寫轉小寫、計算欄位數
function clean_csv(line, n, i, out) {
n = split(line, f, ",")
for (i=1; i<=n; ++i) {
gsub(/^[ \t]+|[ \t]+$/, "", f[i])
f[i] = tolower(f[i])
out = (i==1 ? "" : out ",") f[i]
}
return out
}
{ print clean_csv($0) }
awk 函數威力在於「資料流即參數、字串即物件」。掌握 gsub/sub 替換、split 解析、自訂函數區域變數模擬,即可將複雜資料邏輯封裝為可重用模組。