GNU awk 手册的第 3.4节如下
要在括号表达式中包含字符“\”、“]”、“-”或“^”之一,请在其前面放置“\”。例如:
[d\]]
匹配“d”或“]”。此外,如果您将“]”放在开头“[”之后,则结尾括号将被视为要匹配的字符之一。括号表达式中的 ‘\’ 的处理与其他 awk 实现兼容,并且也是 POSIX 所要求的。
另一方面,的部分没有将 列为具有特殊含义。以下是使用 GNU awk(版本 5.3.1)和 GNU grep(版本 3.11)进行的一些实验,这些实验揭示了对括号表达式中的 的冲突处理:\]
\
$ echo d | awk '/[d\]]/'
d
$ echo d | grep -E '[d\]]'
$ echo ']' | awk '/[d\]]/'
]
$ echo ']' | grep -E '[d\]]'
问题是: GNU awk 文档声称GNU awk 中括号表达式
的处理是 POSIX 规定的,这是错误的吗?还是我忽略了什么?换句话说,GNU awk 是否违反了 POSIX 规范?\
0
最佳答案
3
\
允许 awk 将括号表达式解释为转义字符的POSIX参考位于中的正则表达式下的表中(重点是我的,特别注意表格的最后两行):
…这些转义序列应在括号表达式的内部和外部被识别…
转义序列 描述 意义 \"
<反斜杠> <引号> 在词汇标记 STRING 中,字符。否则未定义。 \/
<反斜杠> <斜杠> 在词汇标记 ERE 中,<slash> 字符。否则未定义。 \ddd
一个 <backslash> 字符,后跟一个、两个或三个八进制数字的最长序列 (01234567)。… 用一位、两位或三位八进制整数表示的字符… \., \[, \(,\*, \+, \?, \{, \|, \^, \$
<backslash> 字符后跟在 ERE 中具有特殊含义的字符…而不是 <backslash>。 在词汇标记 ERE 中,当不在括号表达式内时,序列应表示其自身。否则未定义。 \\
两个 <反斜杠> 字符。 在词汇标记 ERE 中,序列应代表其自身…… \c
<反斜杠> 字符后跟本表或 XBD 5. 文件格式符号 ( ) 中的表中未描述的任何字符 '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v'
。不明确的
这意味着在符合 POSIX 标准的awk
括号表达式之内或之外的\\
被要求表示文字,\
而 的含义\c
,其中c
是表中未列出的任何字符(例如]
),POSIX 未定义,因此gawk
可以随意处理它,例如,可以[d\]]
表示“d
或]
”。
因此,不,在处理 时gawk
并没有违反(它取代了用于描述 awk 行为的\
) ,因为它是\
按照 所要求的方式[\\]
和允许的方式(因为其含义未定义)进行处理的[d\]]
。
18
-
那么,gawk 文档中声称匹配“d”或“]”显然是错误的
[d\]]
,不是吗?POSIX 没有强制要求这样做;它可能匹配,但不必匹配。这种构造不能保证可移植。
– -
POSIX 指出这
[d\]]
是未定义的行为,因此任何 awk 变体(例如 BSD 或 GNU)都可以将其定义为实现者想要的任何含义。gawk 文档指出这[d\]]
意味着d
或]
gawk 中的– 这在 gawk 文档中并不是错误,就像定义函数的作用或部分中gensub()
的值一样,因为这就是 gawk 的含义。$0
END
–
-
1关于“该构造不能保证可移植。” – gawk 文档并未声称它在其他 awk 中的含义与在 gawk 中的含义相同,只是在 gawk 中的含义相同。一般来说,如果您希望代码可移植,则应避免在代码中使用任何行为未由 POSIX 定义的构造(不幸的是,现在的最新规范中也有一些已定义但几乎没有 awk 实现的构造),无论它在您使用的工具变体中是如何定义的。
– -
2@M.NejatAydin 我与 gawk 提供商 Arnold 进行了交谈 – 他将在 gawk 手册中添加更多关于此问题的解释性文字,并且我将针对 POSIX 开具一张票据,以改进标准中对此领域的描述。
–
-
另请注意,
gawk --posix '/[d\>]/'
会发出警告,而gawk --posix '/[d\]]/'
不会。虽然\>
是 GNU 扩展,但两个括号表达式对于 POSIX 都是无效的。
–
|
规定
括号表达式要么是匹配列表表达式,要么是非匹配列表表达式。它由一个或多个表达式组成:普通字符、排序元素、排序符号、等价类、字符类或范围表达式。如果右方括号 ( ‘]’ ) 出现在列表中的第一个位置(如果有,则在初始脱字符 ( ‘^’ 之后),则它将失去其特殊含义并在括号表达式中表示自身。否则,它将终止括号表达式,除非它出现在排序符号中(例如 “[.].]” )或者是排序符号、等价类或字符类的结尾。特殊字符 ‘.’、’*’、'[‘ 和 ‘\’(分别为句点、星号、左方括号和反斜杠)将在括号表达式中失去其特殊含义。
字符序列“[.”、“[=”和“[:”(左方括号后跟句点、等号或冒号)”在括号表达式中应为特殊字符,用于分隔排序符号、等价类表达式和字符类表达式。这些符号后应跟有效表达式和匹配的终止序列“.]”、“=]”或“:]”,如以下各项所述(…)
所以
如果将 ‘]’ 放在开头 ‘[‘ 之后,则结尾括号将被视为要匹配的字符之一
符合上述规定,但
[d\]]
据我理解,这并不意味着 匹配“d”或“]”,因为第一个]
是终止的,因为它既不是第一个字符,也不是排序符号、等价类或字符类的元素。
0
|
通常,创建字符类比担心需要多少个反斜杠(以及每层封装会“吃掉”多少个反斜杠)更容易。因此,如果您想要一个ERE
可以在grep -E
和awk
用于捕获 "d"
(仅小写字母)和/或"]"
(右方括号)的统一,那么请执行
awk '/[]d]/'
或者awk '$0 ~ "[]d]"'
grep -E '[]d]'
只有^
(仅适用于累积字符类,并且仅当它是字符类中最左侧的项目时)和\
需要在字符类中进行特殊的反斜杠处理。其他特殊项目(如]
和)-
可以通过在类中进行战略性放置来避免使用反斜杠。
取反^
(即除插入符号之外的任何语言环境有效字符)—> [^^]
。
我通常将-
或\\
放在 char 类的最右边,]
最左边。如果您需要-
and \
:= [-
… \\]
。如果您需要所有这三个 { ]
, -
, \
},也许[]-
… \\]
。通过\\
尽可能放置在最右边,它们被误认为是除反斜杠本身之外的任何转义序列的可能性为零。
如果可能的话,通过字符范围捕获这几个字符,并完全避免使用反斜杠 – 例如,ASCII
通过明确列出字符范围来捕获所有标点符号,可以这样做
awk '/[!-/:-@[-\140{-~]/'
(gawk / mawk
)
awk '/[!-\/:-@[-\140{-~]/'
(nawk
)
awk '$0 ~ "[!-/:-@[-\140{-~]"'
(我使用它 \140
是因为在我的代码中我不喜欢在任何地方使用物理反引号,但是使用它的字符串版本是安全\140
的\\140
)
此规则的唯一例外是,如果您需要]
限制字符范围的上限。在这种情况下,选择您的毒药:
awk '/[[-\]]/'
或者awk '/[][\\]/'
|
|