如何在 awk 中使用正则表达式

使用正则表达式通过动态和复杂的模式定义来搜索代码。
116 位读者喜欢这个。
Coding on a computer

在 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 后跟 el 的记录。

在方括号内添加 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] 选择 ad
[a-d] 选择 ad 之间的任何字符 (a、b、c 或 d)
[^a-d] 选择 ad 之外的任何字符 (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) 匹配单词 redordered,但不匹配任何以其他顺序包含所有这三个字母的单词(例如单词 order)。

Awk 就像带有 sub() 和 gsub() 的 sed

Awk 具有多个执行查找和替换操作的函数,很像 Unix 命令 sed。这些都是函数,就像 printprintf 一样,可以在 awk 规则中使用,以将字符串替换为新字符串,无论新字符串是字符串还是变量。

sub 函数将(记录中的)第一个匹配实体替换为替换字符串。例如,如果您在 awk 脚本中有此规则

{ sub(/apple/, "nut", $1);
    print $1 }

在示例文件 colours.txt 上运行它会产生此输出

name
nut
banana
raspberry
strawberry
grape
nut
plum
kiwi
potato
pinenut

applepineapple 都被替换为 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 非常强大,可以轻松取代 grepsedtr 以及 sort 等等许多工具,从某种意义上说,您是对的。但是,awk 只是一个工具箱中的一个工具,该工具箱充满了出色的选项。您可以选择使用什么以及何时使用它,因此不要觉得您必须使用一个工具来完成每项大小工作。

话虽如此,awk 确实是一个功能强大的工具,具有许多出色的功能。您使用得越多,就越了解它。记住它的功能,并不时地求助于它,以便您可以逐渐熟悉它。

我们的下一篇文章将介绍 Awk 中的循环,请稍后回来!


本文改编自 Hacker Public Radio 的一集,这是一个社区技术播客。

接下来阅读什么
Seth Kenlon
Seth Kenlon 是一位 UNIX 极客、自由文化倡导者、独立多媒体艺术家和 D&D 爱好者。他曾在电影和计算机行业工作,经常同时从事这两个行业。

2 条评论

我认为您的代码字符串“adding an o inside the square brackets”在方括号内缺少一个“o”。

Creative Commons 许可本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
© . All rights reserved.