如何在 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)。

类似 sed 的 Awk,带有 sub() 和 gsub()

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 非常强大,可以轻松地替换 grepsed 以及 trsort 等等,从某种意义上说,你是对的。 但是,awk 只是一个工具箱中的一个工具,该工具箱中充满了很棒的选项。 你可以选择使用什么以及何时使用,因此不要觉得你必须使用一种工具来完成大小事务。

话虽如此,awk 确实是一个具有许多强大功能的强大工具。 你使用它的次数越多,你就越了解它。 记住它的功能,并偶尔返回来,这样你就可以轻松地使用它。

我们的下一篇文章将介绍 Awk 中的循环,所以请尽快回来!


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

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

2 条评论

我认为你的代码字符串“在方括号内添加 o”在方括号内缺少一个“o”。

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