理解awk分隔符-在基于正则表达式的字段分隔符中转义

理解awk分隔符-在基于正则表达式的字段分隔符中转义,awk,escaping,delimiter,Awk,Escaping,Delimiter,我有以下shell命令: awk -F'\[|\]' '{print $2}' 这个命令在做什么?是否使用分隔符[sometext]拆分为字段 例如: 编者按:只有Ubuntu默认情况下才会生成上述输出。明显的目的是将文字[和]视为字段分隔符,即,通过[和/或]的每次出现,将每个输入记录拆分为字段,其与示例行一起生成字段1$1,行为字段2$2,并作为最后一个字段$3传递给awk 这是通过使用交替|的正则表达式实现的,交替|的任一侧定义了一个字段分隔符:正则表达式中的\[和\]需要表示文字[和]

我有以下shell命令:

awk -F'\[|\]' '{print $2}'
这个命令在做什么?是否使用分隔符[sometext]拆分为字段

例如:

编者按:只有Ubuntu默认情况下才会生成上述输出。

明显的目的是将文字[和]视为字段分隔符,即,通过[和/或]的每次出现,将每个输入记录拆分为字段,其与示例行一起生成字段1$1,行为字段2$2,并作为最后一个字段$3传递给awk

这是通过使用交替|的正则表达式实现的,交替|的任一侧定义了一个字段分隔符:正则表达式中的\[和\]需要表示文字[和],因为默认情况下,[和]是具有特殊语法含义的所谓元字符。 注意,awk总是将FS变量-F选项的值解释为正则表达式

但是,正确的形式是“\\[\\]”:

也就是说,使用字符集[…]而不是交替的更简洁的版本是:

请注意,在[inclusion[…]之前小心地放置了]以实现此功能,以及封闭[…]现在如何具有特殊意义:它们封闭一组字符,其中任何字符都匹配

至于为什么在“\\[\\]”中需要2个\实例:

作为一个独立的正则表达式,\[\\]将在以下情况下工作:

\[匹配文字][ \]匹配文字] |是与其中一个匹配的替换。 但是,Awk的字符串处理是第一位的:

由于在字符串中进行\处理,它应该在解释为正则表达式之前将\[\\]减少到[\\]

然而,不幸的是,举例来说,Ubuntu上的默认Awk在这个特定场景中依赖于猜测 [|]被解释为正则表达式,然后只匹配单个文本|

因此,当您打算将单个\作为正则表达式的一部分传递时,健壮且可移植的方法是在字符串文本中使用\\

这段引语很好地概括了这一点:

要将反斜杠转换为字符串中的正则表达式,必须键入两个反斜杠

[1] 实施差异:

不幸的是,至少有1个主要的Awk实现在字符串文本中的正则表达式元字符前面有一个\时求助于猜测

BSD/macOS Awk和GNU Awk的行为是可预测的,GNU Awk在发现单前缀regex元字符时也会发出有用的警告:

# GNU Awk: Predictable string-first processing + a helpful warning.
echo 'a[b]|c' | gawk -F'\[|\]' '{print $2}'
gawk: warning: escape sequence '\[' treated as plain '['
gawk: warning: escape sequence '\]' treated as plain ']'
c

# BSD/macOS Awk: Predictable string-first processing, no warning.
echo 'a[b]|c' | awk -F'\[|\]' '{print $2}'
c

# Mawk: *Guesses* that a *regex* was intended.
#       The unambiguous form -F'\\[|\\]' works too, fortunately.
echo 'a[b]|c' | mawk -F'\[|\]' '{print $2}'
b
可选读取:Awk脚本中的正则表达式文本 Awk支持/../中包含的正则表达式文本,使用它可以绕过双转义问题

然而:

这些不变的文本仅在Awk脚本中可用, 而且,看起来,您只能将它们用作模式或函数参数—您不能将它们存储在变量中。 因此,即使/\[\\]/原则上等同于\\[\\\],您也不能使用以下内容,因为无法将正则表达式文字赋值给特殊变量FS:

$ echo "this [line] passed to awk" | awk -F'\\[|\\]' '{print $2}'
line
$ echo "this [line] passed to awk" | awk -F'[][]' '{print $2}'
line
# GNU Awk: Predictable string-first processing + a helpful warning.
echo 'a[b]|c' | gawk -F'\[|\]' '{print $2}'
gawk: warning: escape sequence '\[' treated as plain '['
gawk: warning: escape sequence '\]' treated as plain ']'
c

# BSD/macOS Awk: Predictable string-first processing, no warning.
echo 'a[b]|c' | awk -F'\[|\]' '{print $2}'
c

# Mawk: *Guesses* that a *regex* was intended.
#       The unambiguous form -F'\\[|\\]' works too, fortunately.
echo 'a[b]|c' | mawk -F'\[|\]' '{print $2}'
b
# !! DOES NOT WORK in any of the 3 major Awk implementations.
#    Note that nothing is output, and no error/warning is displayed.
$ echo 'a[b]|c' | awk 'BEGIN { FS=/\[|\]/ } { print $2 }'

# Using a double-escaped *string* to house the regex again works as expected:
$ echo 'a[b]|c' | awk 'BEGIN { FS="\\[|\\]" } { print $2 }'
b