在 awk 中,正则表达式 (regex) 允许动态和复杂的模式定义。您不仅限于搜索简单的字符串,还可以搜索模式中的模式。
在 awk 中使用正则表达式匹配行的语法是
word ~ /match/
其相反的情况是不匹配模式
word !~ /match/
如果您还没有创建示例文件,请从我们的上一篇文章中创建
name color amount
apple red 4
banana yellow 6
strawberry red 3
raspberry red 99
grape purple 10
apple green 8
plum purple 2
kiwi brown 4
potato brown 9
pineapple yellow 5
将文件另存为 colours.txt 并运行
$ awk -e '$1 ~ /p[el]/ {print $0}' colours.txt
apple red 4
grape purple 10
apple green 8
plum purple 2
pineapple yellow 5
您已选择所有包含字母 p 后跟 e 或 l 的记录。
在方括号内添加 o 会创建一个新的匹配模式
$ awk -e '$1 ~ /p[o]/ {print $0}' colours.txt
apple red 4
grape purple 10
apple green 8
plum purple 2
pineapple yellow 5
potato brown 9
正则表达式基础知识
某些字符在正则表达式中使用时具有特殊含义。
锚点
锚点 | 功能 |
---|---|
^ | 指示行的开头 |
$ | 指示行的结尾 |
\A | 表示字符串的开头 |
\z | 表示字符串的结尾 |
\b | 标记单词边界 |
例如,此 awk 命令打印任何包含 r 字符的记录
$ awk -e '$1 ~ /r/ {print $0}' colours.txt
strawberry red 3
raspberry red 99
grape purple 10
添加 ^ 符号以仅选择 r 出现在行首的记录
$ awk -e '$1 ~ /^r/ {print $0}' colours.txt
raspberry red 99
字符
字符 | 功能 |
---|---|
[ad] | 选择 a 或 d |
[a-d] | 选择 a 到 d 之间的任何字符 (a、b、c 或 d) |
[^a-d] | 选择除 a 到 d 之外的任何字符 (e、f、g、h…) |
\w | 选择任何单词 |
\s | 选择任何空白字符 |
\d | 选择任何数字 |
w、s 和 d 的大写版本是取反;例如,\D 不选择任何数字。
POSIX 正则表达式为字符类提供了简单的助记符
POSIX 助记符 | 功能 |
---|---|
[:alnum:] | 字母数字字符 |
[:alpha:] | 字母字符 |
[:space:] | 空格字符(例如空格、制表符和换页符) |
[:blank:] | 空格和制表符 |
[:upper:] | 大写字母字符 |
[:lower:] | 小写字母字符 |
[:digit:] | 数字字符 |
[:xdigit:] | 十六进制数字字符 |
[:punct:] | 标点符号字符(即,不是字母、数字、控制字符或空格字符的字符) |
[:cntrl:] | 控制字符 |
[:graph:] | 既可打印又可见的字符(例如,空格是可打印的但不可见,而 a 既可打印又可见) |
[:print:] | 可打印字符(即,不是控制字符的字符) |
量词
量词 | 功能 |
---|---|
. | 匹配任何字符 |
+ | 修改前面的集合以表示一次或多次 |
* | 修改前面的集合以表示零次或多次 |
? | 修改前面的集合以表示零次或一次 |
{n} | 修改前面的集合以表示正好 n 次 |
{n,} | 修改前面的集合以表示n 次或更多次 |
{n,m} | 修改前面的集合以表示介于 n 和 m 次之间 |
许多量词修改了它们前面的字符集。例如,. 表示出现恰好一次的任何字符,但 .* 表示任何或没有字符。这是一个示例;仔细查看正则表达式模式
$ printf "red\nrd\n"
red
rd
$ printf "red\nrd\n" | awk -e '$0 ~ /^r.d/ {print}'
red
$ printf "red\nrd\n" | awk -e '$0 ~ /^r.*d/ {print}'
red
rd
同样,花括号中的数字指定某事物出现的次数。要查找 e 字符正好出现两次的记录
$ awk -e '$2 ~ /e{2}/ {print $0}' colours.txt
apple green 8
分组匹配
量词 | 功能 |
---|---|
(red) | 括号表示括起来的字母必须连续出现 |
| | 在分组匹配的上下文中表示或 |
例如,模式 (red) 匹配单词 red 和 ordered,但不匹配任何以其他顺序包含所有这三个字母的单词(例如单词 order)。
Awk 就像带有 sub() 和 gsub() 的 sed
Awk 具有多个执行查找和替换操作的函数,很像 Unix 命令 sed。这些都是函数,就像 print 和 printf 一样,可以在 awk 规则中使用,以将字符串替换为新字符串,无论新字符串是字符串还是变量。
sub 函数将(记录中的)第一个匹配实体替换为替换字符串。例如,如果您在 awk 脚本中有此规则
{ sub(/apple/, "nut", $1);
print $1 }
在示例文件 colours.txt 上运行它会产生此输出
name
nut
banana
raspberry
strawberry
grape
nut
plum
kiwi
potato
pinenut
apple 和 pineapple 都被替换为 nut 的原因是两者都是其记录的第一个匹配项。如果记录不同,则结果可能会有所不同
$ printf "apple apple\npineapple apple\n" | \
awk -e 'sub(/apple/, "nut")'
nut apple
pinenut apple
gsub 命令替换所有匹配项
$ printf "apple apple\npineapple apple\n" | \
awk -e 'gsub(/apple/, "nut")'
nut nut
pinenut nut
Gensub
这些函数的更复杂版本,称为 gensub(),也可用。
gensub 函数允许您使用 & 字符来回忆匹配的文本。例如,如果您的文件包含单词 Awk 并且您想将其更改为 GNU Awk,则可以使用此规则
{ print gensub(/(Awk)/, "GNU &", 1) }
这会搜索字符组 Awk 并将其存储在内存中,由特殊字符 & 表示。然后它将字符串替换为 GNU &,意思是 GNU Awk。末尾的 1 字符告诉 gensub() 替换第一次出现。
$ printf "Awk\nAwk is not Awkward" \
| awk -e ' { print gensub(/(Awk)/, "GNU &",1) }'
GNU Awk
GNU Awk is not Awkward
何时何地使用
Awk 是一个强大的工具,而正则表达式很复杂。您可能会认为 awk 非常强大,可以轻松取代 grep、sed 和 tr 以及 sort 等等许多工具,从某种意义上说,您是对的。但是,awk 只是一个工具箱中的一个工具,该工具箱充满了出色的选项。您可以选择使用什么以及何时使用它,因此不要觉得您必须使用一个工具来完成每项大小工作。
话虽如此,awk 确实是一个功能强大的工具,具有许多出色的功能。您使用得越多,就越了解它。记住它的功能,并不时地求助于它,以便您可以逐渐熟悉它。
我们的下一篇文章将介绍 Awk 中的循环,请稍后回来!
本文改编自 Hacker Public Radio 的一集,这是一个社区技术播客。
2 条评论