输入是
AZE D11/879\x0Dabc\x0D\x0A\x1E!DEF F11/999
awk 脚本将字段分隔符设置为“\x0D”(我尝试过使用或不使用转义反斜杠。
awk 脚本是
BEGIN {FS="\\x0D"}
{print NF}
它应该输出 3,因为字段分隔符出现 2 次,但它输出 1 表示它未被识别。
在 awk 中提供正则表达式有两种方法 - 静态正则表达式(又名正则表达式文字)写为
/regexp/
和动态正则表达式(又名计算正则表达式)写为 "regexp"
并在正则表达式上下文中使用。字段分隔符只是具有一些附加行为的正则表达式,因此我们只考虑一般的正则表达式来解释示例中发生的情况。
split()
函数采用字段分隔符(用于我们目的的正则表达式)作为第三个参数,因此它提供了一个很好的测试床:
使用静态正则表达式:
$ awk '{print split($0,a,/\x0D/)}' file
1
上面的
\
是对x
的转义,它不是字面意思的\
。为此,您需要转义 \
本身:
$ awk '{print split($0,a,/\\x0D/)}' file
3
如果我们使用动态正则表达式而不是上面的静态正则表达式会怎样?
$ awk '{print split($0,a,"\x0D")}' file
1
$ awk '{print split($0,a,"\\x0D")}' file
1
$ awk '{print split($0,a,"\\\x0D")}' file
' is not a known regexp operator FNR=1) warning: regexp escape sequence `\
1
$ awk '{print split($0,a,"\\\\x0D")}' file
3
上面的行为是因为 awk 首先解析字符串以将其转换为正则表达式(使用了一层转义字符),然后在 using 将其作为正则表达式时第二次解析它(使用了第二层转义字符) ).
不幸的是,当您指定
FS
时,没有选项将其指定为文字正则表达式,它始终使用字符串指定,因此是动态正则表达式,因此需要额外的转义层:
$ awk -v FS='\x0D' '{print NF}' file
1
$ awk -v FS='\\x0D' '{print NF}' file
1
$ awk -v FS='\\\x0D' '{print NF}' file
' is not a known regexp operatorence `\
1
$ awk -v FS='\\\\x0D' '{print NF}' file
3
现在 - 如果您在脚本的 shell 部分使用了错误类型的引号(即
"
而不是 '
)怎么办?然后你会引入更多的痛苦,因为现在你甚至在 awk 看到并解析它两次之前邀请 shell also 解析该字符串:
$ awk -v FS="\\\\x0D" '{print NF}' file
1
$ awk -v FS="\\\\\x0D" '{print NF}' file
' is not a known regexp operatorence `\
1
$ awk -v FS="\\\\\\x0D" '{print NF}' file
' is not a known regexp operatorence `\
1
$ awk -v FS="\\\\\\\x0D" '{print NF}' file
3
这与 awk 内部使用双引号的情况不同,因为它们都包含在单引号内,因此已经受到 shell 的保护:
$ awk 'BEGIN{FS="\\\\x0D"} {print NF}' file
3
因此 - 在 shell 中,始终使用最严格的引号(
'
超过 "
超过无),除非您有非常具体的理由不这样做,并且在使用正则表达式或字段分隔符时,始终使用文字 /.../
而不是动态 "..."
,再次强调,除非您有非常具体的理由不这样做。
上面奇怪的、被截断的错误消息是由于我们提供的转义序列而导致该工具尝试打印的
\r
,它们实际上都是 warning: regexp escape sequence '\^M' is not a known regexp operator
文字反斜杠需要两个反斜杠,因为
\
是转义字符:
$ echo 'AZE D11/879\x0Dabc\x0D\x0A\x1E!DEF F11/999' |
awk 'BEGIN{ FS="\\\\x0D" } { print NF }'
3
我通常将反斜杠强制放入其自己的字符类中。
split($0, arr, /[\\]x0D/)
split($0, arr, "[\\\\]x0D")
这样,所有反斜杠都与随后出现的任何其他字节隔离,如果我缺少反斜杠,它永远不会被误解为试图匹配字节
\x0D
(0x0D
,即"\r"
)。