考虑字符串hello(world)
。
我想使用awk
调用来提取world
.
这是我的第一次尝试,输出是一个空字符串,没有错误。
echo 'hello(world)' | awk -F'(|)' '{print $2}'
我的第二次尝试是使用字符类,这产生了预期的行为:
echo 'hello(world)' | awk -F'[()]' '{print $2}'
然而,鉴于 awk 的文档声称字段分隔符可以是正则表达式,我预计第一次尝试会起作用。
这是我的 awk 版本:
$ awk --version
GNU Awk 5.0.1, API: 2.0 (GNU MPFR 4.0.2, GNU MP 6.2.0)
Copyright (C) 1989, 1991-2019 Free Software Foundation.
为什么表达式(|)
达不到预期的结果?
正则表达式的含义与, the
(|)
相同,只是不必要地将其放在一组中。和regexp 分组元字符对于编写正则表达式非常有用,比如可以在前面加上or ,或者用于稍后需要捕获组进行反向引用的情况,但不是在这里。|
(
)
(
)
(a|b)c
c
a
b
如果您不想
(
被)
视为正则表达式元字符,那么您需要转义开头(
,并且仅转义开头(
,因为如果结尾跟随未转义的开头,则结尾)
只是一个正则表达式元字符(
,就像]
如果它紧随其后,则仅是一个正则表达式元字符接下来是一个未转义的开口[
。如果您还选择转义)
or]
that 在每个 POSIX 中都是技术上未定义的行为,就像转义任何其他文字字符一样,尽管我个人从未遇到过不将其视为文字字符的 awk 变体。就像您编写动态 regexp时一样,当您编写字段分隔符字符串时,它会经历 2 个解析阶段,首先当字符串转换为您定义的正则表达式/字段分隔符时,然后再次在期间使用它时代码的执行。鉴于此,如果要使用
\
转义 FS 中的元字符,则需要转义两次,即\\
。或者,您可以将其放在括号表达式内,而不是在元字符之前放置 2 个反斜杠[...]
,这也将使其成为字面意思。IMO 执行后者使您的代码比加倍转义更清晰,而且如果您决定“转义”两个字符,则[)]
不会出现技术上未定义行为的小问题。\\)
因此,要制作
(
和)
字面量,您可以在任何 awk 中编写以下任一内容:awk -F'\\(|)' '{print $2}'
awk -F'[(]|)' '{print $2}'
awk -F'[()]' '{print $2}'
我的偏好 FWIW 是#3,即使它
)
是在括号表达式内部或外部的文字,因为它比前两个替代方案更简洁。在摆弄了
\
各种字符前面之后,我终于意识到问题出在 ,()
而不是字符|
。而且,()
需要进行双重转义。下面的表达式可以达到预期的结果:
奇怪的是,它省略右括号上的转义似乎也可以正常工作:
来自正则表达式运算符
awk
考虑到这一点,您可能会通过编写获得所需的效果