我们把**语言称为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 文件的门道。 他们学会了如何向系统添加新用户、如何更新用户信息,以及如何删除旧用户。
在处理 /etc/passwd 文件的过程中,Alex 注意到了一些奇怪的地方。 有些用户的主目录很奇怪,很不寻常。 有些用户的主目录被设成了 /dev/null,还有一些用户的主目录被设成了根本不存在、莫名其妙的路径。
Alex 意识到,这些用户并不是真人,而是黑客创建的虚假账号。 黑客找到了一种利用系统漏洞的方法,创建这些虚假账号来入侵 Cyberspace。
Alex 知道自己必须采取行动。 他们用 awk 分析 /etc/passwd 文件,并写了一个脚本来找出所有虚假账号。 然后他们和团队其他成员一起删除了这些账号,并修补了让黑客得以创建这些账号的漏洞。
多亏 Alex 用上了 awk,团队才得以找出并删除这些虚假账号,让 Cyberspace 对每个人都更安全。 系统管理员继续管理着 /etc/passwd 文件,让它保持最新、安全,并确保只有经过授权的用户才能访问系统。
现在,轮到你来做一名像 Alex 一样的系统管理员了。
下面是解这道练习时还需要用到的一些 AWK 语法。
布尔运算符和其他语言类似:
| 运算 | 示例 |
|---|---|
| 与 | expr1 && expr2 |
| 或 | expr1 || expr2 |
| 非 | ! expr |
调用函数的语法你一定很熟悉:
function greet(name) {
print "Hello", name
}
BEGIN {
greet("Mary") # prints "Hello Mary"
}
写一个 awk 程序,打印 passwd 文件中每一行里以冒号分隔的第一个字段。
写一条 awk 命令,打印输入文件中每条记录的行号。 只打印行号,不要打印其他任何信息。
在 Cyberspace 中,“有效”的主目录以 /home 或 /root 开头。
打印输入文件中主目录无效的记录。
打印主目录有效并且登录 shell 是 bash 的记录。