如何在awk中将Shell正则变量作为更大正则表达式的一部分使用?
问题:如何在awk中使用变量作为更大正则表达式的一部分
我在脚本里尝试执行这段代码,目的是匹配配置文件中[Global](大小写不敏感)所在行之后的内容:
CONTEXT_PAT1="\[[gG][lL][oO][bB][aA][lL]\]" awk -v pat1="$CONTEXT_PAT1" 'f;/^[:space:]*pat1[:space:]*$/{f=1}' ${CONFIG_FL}
但调试时发现实际执行的命令是:
++ awk -v 'pat1=\[[gG][lL][oO][bB][aA][lL]\]' 'f;/^[:space:]*pat1[:space:]*$/{f=1}'
显然awk把pat1当成了字面量字符串,而不是变量。我预期的执行效果应该是让变量pat1的内容替换到正则里,变成这样:
++ awk -v 'pat1=\[[gG][lL][oO][bB][aA][lL]\]' 'f;/^[:space:]*\[[gG][lL][oO][bB][aA][lL]\][:space:]*$/{f=1}'
我查了相关资料,但现有方案大多是直接传入正则变量,没涉及把变量作为更大正则的一部分的场景,该怎么实现?
这是个很典型的awk变量使用误区,核心问题在于:awk的/.../是正则常量,里面的内容会被当作字面量解析,不会识别变量。要把变量嵌入到更大的正则表达式里,有两种靠谱的解决方式:
方法1:在awk内部用字符串拼接构建正则(推荐)
使用awk的匹配运算符~,把变量和前后的正则片段拼接成完整的字符串,这样awk就会把整个拼接后的内容当作正则表达式处理。修改后的代码如下:
CONTEXT_PAT1="\[[gG][lL][oO][bB][aA][lL]\]" awk -v pat1="$CONTEXT_PAT1" 'f; $0 ~ "^[[:space:]]*" pat1 "[[:space:]]*$" {f=1}' "${CONFIG_FL}"
这里要注意两个细节:
- 空白字符类的正确写法是
[[:space:]],而不是你原来的[:space:]——POSIX字符类必须放在方括号内部才生效 - 用
"${CONFIG_FL}"代替${CONFIG_FL},避免文件名包含空格时出现问题
方法2:在shell层面预先拼接完整正则
如果你更习惯在shell中处理字符串拼接,也可以先把完整的正则表达式组装好,再传给awk:
CONTEXT_PAT1="\[[gG][lL][oO][bB][aA][lL]\]" FULL_PAT="^[[:space:]]*${CONTEXT_PAT1}[[:space:]]*$" awk -v fullpat="$FULL_PAT" 'f; $0 ~ fullpat {f=1}' "${CONFIG_FL}"
这种方式先在shell中把变量和前后的正则片段拼接成完整的正则字符串,再通过-v传给awk,同样用~来匹配变量中的正则内容。
额外提示
- 如果你使用的是GNU awk(gawk)4.0及以上版本,还可以用动态正则表达式语法
@/.../,比如:
不过这种写法兼容性不如前两种,建议优先用前两种方法。awk -v pat1="$CONTEXT_PAT1" 'f; $0 ~ @/^[[:space:]]*/ pat1 @/[[:space:]]*$/{f=1}' "${CONFIG_FL}"
内容的提问来源于stack exchange,提问作者dig_123
相关产品推荐
相关产品推荐

