我們會將這門 語言 稱為AWK,並將解讀 AWK 程式的 執行檔 稱為**awk或gawk**。
一個 AWK 程式是由模式-動作配對組成。
pattern1 { action1 }
pattern2 { action2 }
...
模式可以是對輸入進行比對的正規表示式,也可以是任何能產生 true/false 值的運算式。
動作則是一個或多個 AWK 指令。外層的大括號是必要的。
如果模式的結果為 true,就會執行對應的動作。
AWK 會將輸入解析成一連串的記錄,再把每筆記錄分割成零個或多個欄位。
預設行為是:
模式可以省略,此時動作會_對每一筆輸入記錄_執行。
動作也可以省略,此時預設動作是印出目前的記錄。
有兩種特殊模式經常會用到。
BEGIN會在讀取任何輸入之前執行對應的動作。END會在讀取完所有輸入之後執行對應的動作。你可以用$1、$2、$3等方式取用欄位。
目前的記錄是$0。
以下是一些其他常用的內建變數。
RS是輸入記錄分隔符。如前所述,它的預設值是換行。FS是輸入欄位分隔符。這些變數通常會在BEGIN動作區塊中設定。
這些變數會在程式執行期間由 AWK 自動設定。
NF會儲存目前記錄的欄位數量。
$NF。NR會儲存目前的記錄編號。
NR會保存到目前為止已處理的記錄總數。FNR會儲存目前輸入檔案中目前的記錄編號。
NR == FNR {action}
意思是「如果累計的記錄編號等於目前檔案的記錄編號」。這只有在_第一個輸入檔案_的記錄中才可能成立。AWK 使用的真值概念和 C 相同。
0為 false。由於 AWK 是文字處理語言,真值也會延伸到字串。
""為 false。註解以#字元開頭,延伸到該行結尾。
在類 Unix 系統中,/etc/passwd包含了使用者的資訊。每位使用者各佔一行,欄位之間以冒號分隔。
如要列出使用者名稱:
awk '
BEGIN { FS = ":" }
{ print $1 }
' /etc/passwd
請注意,{print $1}動作沒有模式,因此會對每一筆記錄執行。
如果只想輸出使用 bash 作為登入 shell 的使用者,可以這樣寫:
awk '
BEGIN { FS = ":" }
$7 == "/bin/bash" { print $1 }
' /etc/passwd
從前從前,有一座熱鬧繁華的城市,叫做 Cyberspace。 Cyberspace 是一座數位大都會,每天有數百萬名居民登入和登出。 為了追蹤所有這些使用者,Cyberspace 有一個特別的檔案,叫做 /etc/passwd。
/etc/passwd 檔案就像是這座城市的電話簿。 它列出了系統上每一個擁有帳號的使用者,以及每位使用者的一些重要資訊:
| n | 欄位 |
|---|---|
| 1 | 使用者名稱 |
| 2 | 密碼(「x」表示基於安全考量,實際密碼儲存在別的地方) |
| 3 | UID,唯一的使用者數值 ID |
| 4 | GID,唯一的群組數值 ID(通常與 UID 相同) |
| 5 | 使用者資訊(通常是使用者的全名,但也可以包含其他資訊) |
| 6 | 家目錄 |
| 7 | 登入 shell |
這些欄位以冒號字元分隔。 以下是一個典型的條目:
glennj:x:1010:1010:Glenn Jackman:/home/glennj:/usr/local/bin/fish
這個檔案由一群系統管理員管理,他們負責建立新帳號、更新現有帳號,以及移除舊帳號。 系統管理員是 Cyberspace 的守門人,確保只有獲得授權的使用者才能存取系統。
有一天,團隊新聘了一位叫做 Alex 的系統管理員。 Alex 對接下這份工作感到很興奮,也很快就摸透了 /etc/passwd 檔案的來龍去脈。 他們學會了如何把新使用者加入系統、如何更新使用者資訊,以及如何移除舊使用者。
當 Alex 在處理 /etc/passwd 檔案時,他們注意到了一些奇怪的事。 有些使用者的家目錄很奇怪,或者不太尋常。 有些使用者的家目錄被設成 /dev/null,另一些使用者的家目錄則被設成根本不存在的奇怪路徑。
Alex 意識到這些使用者不是真人,而是駭客建立的假帳號。 駭客找到了利用系統漏洞的方法,並建立了這些假帳號來取得 Cyberspace 的存取權。
Alex 知道自己必須採取行動。 他們使用 awk 分析 /etc/passwd 檔案,並寫了一個指令碼來找出所有假帳號。 接著他們與團隊其他成員合作,移除這些帳號,並修補當初讓駭客得以建立這些帳號的漏洞。
多虧 Alex 使用了 awk,團隊才能找出並移除這些假帳號,讓 Cyberspace 成為對所有人來說更安全的地方。 系統管理員持續管理 /etc/passwd 檔案,讓它保持最新且安全,並確保只有獲得授權的使用者才能存取系統。
現在,輪到你來當像 Alex 一樣的系統管理員了。
這裡還有一些解這道練習需要用到的 AWK 語法。
布林運算子和其他語言很像:
| 運算 | 範例 |
|---|---|
| AND | expr1 && expr2 |
| OR | expr1 || expr2 |
| NOT | ! expr |
呼叫函式的語法也很熟悉:
function greet(name) {
print "Hello", name
}
BEGIN {
greet("Mary") # prints "Hello Mary"
}
寫一個 awk 程式,印出 passwd 檔案中每一行以冒號分隔的第一個欄位。
寫一個 awk 指令,印出輸入檔案中每一筆紀錄的行號。 只印出行號,不要印出其他資訊。
在 Cyberspace 中,「有效」的家目錄會以/home或/root開頭。
印出輸入檔案中家目錄無效的紀錄。
印出家目錄有效且登入 shell 是bash的紀錄。