awk:致命:设置多个字段分隔符时,正则表达式无效

时间:2016-04-22 07:00:55

标签: regex awk gawk

我尝试使用awk来解决Grep regex to select only 10 character。问题包含字符串XXXXXX[YYYYY--ZZZZZ,OP希望在文本中的唯一[--字符串之间打印文本。

如果只有一个-,我会说使用[-[]作为field separator(FS)。这是将FS设置为-[

$ echo "XXXXXXX[YYYYY-ZZZZ" | awk -F[-[] '{print $2}'
YYYYY

棘手的一点是[作为一个字符类也有一个特殊的含义,所以为了使它被正确地解释为可能的FS之一,它不能写在第一个位置。嗯,这是通过说[-[]来完成的。我们已完成匹配-[

但是,在这种情况下,它不是一个而是两个连字符:我想说--[。我不能说[--[]因为连字符也有定义范围的意义。

我能做的就是使用-F"one pattern|another pattern"之类的:

$ echo "XXXXXXXaaYYYYYbbZZZZ" | awk -F"aa|bb" '{print $2}'
YYYYY

因此,如果我尝试将其与--[一起使用,我就无法获得正确的结果:

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk -F"--|[" '{print $2}'
awk: fatal: Invalid regular expression: /--|[/

事实上,甚至没有将[作为其中一个术语:

$ echo "XXXXXXX[YYYYYbbZZZZ" | awk -F"bb|[" '{print $2}'
awk: fatal: Invalid regular expression: /bb|[/

$ echo "XXXXXXX[YYYYYbbZZZZ" | awk -F"bb|\[" '{print $2}'
awk: warning: escape sequence `\[' treated as plain `['
awk: fatal: Invalid regular expression: /bb|[/

$ echo "XXXXXXX[YYYYYbbZZZZ" | awk -F"(bb|\[)" '{print $2}'
awk: warning: escape sequence `\[' treated as plain `['
awk: fatal: Unmatched [ or [^: /(bb|[)/

你看我试图逃避[,括在括号中,没有任何效果。

那么:我该怎么做才能将字段分隔符设置为--[?它有可能吗?

3 个答案:

答案 0 :(得分:3)

恕我直言,如果我们首先查看split()命令正在使用的正则表达式,这是最好的解释,因为它明确显示了使用文字与动态正则表达式将字符串拆分为字段时发生的情况然后我们可以将到现场分隔符。

这使用文字正则表达式(由/ s分隔):

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk '{split($0,f,/\[|--/); print f[2]}'
YYYYY

因此需要对[进行转义,因此[是一个正则表达式元字符,所以它是字面意思。

这些使用动态正则表达式(一个存储为字符串):

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk '{split($0,f,"\\[|--"); print f[2]}'
YYYYY

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk 'BEGIN{re="\\[|--"} {split($0,f,re); print f[2]}'
YYYYY

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk -v re='\\[|--' '{split($0,f,re); print f[2]}'
YYYYY

所以要求[被转义2次,因为awk必须将持有regexp的字符串(最后2个示例中名为re的变量)转换为正则表达式(用完一个反斜杠)用作split()调用中的分隔符(用完第二个反斜杠)。

此:

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk -v re="\\\[|--" '{split($0,f,re); print f[2]}'
YYYYY

将变量内容暴露给shell进行评估,因此需要将[转义3次,因为shell首先解析字符串以尝试扩展shell变量等(使用一个反斜杠)和然后awk必须将持有正则表达式的字符串转换为正则表达式(使用第二个反斜杠),然后将其用作split()调用中的分隔符(使用第三个反斜杠)。

字段分隔符只是一个正则表达式,存储为名为FS的变量(如上面的re),带有一些额外的语义,所以上述所有内容都适用于它,因此:

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk -F '\\[|--' '{print $2}'
YYYYY

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk -F "\\\[|--" '{print $2}'
YYYYY

请注意,我们可以使用括号表达式而不是转义它来对[进行字面处理:

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk '{split($0,f,/[[]|--/); print f[2]}'
YYYYY

然后,当我们添加解析层时,我们不必担心转义转义:

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk -F "[[]|--" '{print $2}'
YYYYY

$ echo "XXXXXXX[YYYYY--ZZZZ" | awk -F '[[]|--' '{print $2}'
YYYYY

答案 1 :(得分:2)

你需要使用双反斜杠来转义双引号字符串中的正则表达式元字符,这样它就会被视为正则表达式元字符(如果你使用单反斜杠)它将被视为ecape序列

$ echo 'XXXXXXX[YYYYYbbZZZZ' | awk -v FS="bb|\\[" '{print $2}'
YYYYY

答案 2 :(得分:2)

这与GNU Awk 3.1.7

echo "XXXXXXX[YYYYY--ZZZZ" | awk -F"--|[[]" '{print $2}'    
echo "XXXXXXX[YYYYYbbZZZZ" | awk -F"bb|[[]" '{print $2}'