awk字段分隔符中正则管道的正确用法及(|)失效原因
awk字段分隔符正则表达式的问题解析
要从字符串hello(world)中提取world,执行以下命令时输出为空且无报错:
echo 'hello(world)' | awk -F'(|)' '{print $2}'
改用字符类作为分隔符则得到预期结果:
echo 'hello(world)' | awk -F'[()]' '{print $2}'
使用的awk版本为:
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.
问题原因
awk默认使用**基本正则表达式(BRE)**处理字段分隔符,你写的(|)在BRE中完全是字面字符,不具备“或”的逻辑:
- 在BRE语法里,
(、)、|都是普通字面字符,没有分组或交替的特殊含义; - 因此
-F'(|)'实际是要求匹配连续的(|)字符串,但原输入hello(world)中根本不存在这个序列,所以awk没有拆分任何字段,整个字符串作为$1,$2自然为空。
而-F'[()]'使用的是字符类语法,在BRE和ERE中都有效,它表示匹配(或)任意一个字符,因此能正确将hello(world)拆分为hello、world、空串三个字段,$2就是目标内容world。
补充:用“或”逻辑实现的正确写法
如果一定要用正则的“或”来匹配(或),可以切换到扩展正则表达式(ERE)模式,或在BRE中转义特殊字符:
# BRE模式:转义括号和|来实现或逻辑 echo 'hello(world)' | awk -F'\\(|\\)' '{print $2}' # GNU awk启用ERE模式的写法 echo 'hello(world)' | awk --re-interval -F'(\\(|\\))' '{print $2}' # ERE模式下更简洁的字符类写法 echo 'hello(world)' | awk -E -F'[()]' '{print $2}'
内容的提问来源于stack exchange,提问作者merlin2011
相关产品推荐
相关产品推荐

