在 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)。
类似 sed 的 Awk,带有 sub() 和 gsub()
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 条评论