我知道RS=
我们可以将记录分隔符设置为空/空字符串;然而 GNUawk
也允许将 RS 定义为正则表达式,所以我决定使用RS='|'
,并且我希望 gawk 能够将其理解为RS=
“空字符串(或者|
)空字符串”,但是将其视为文字|
字符,而当我RS='X|Y'
这样做时正确识别它是正则表达式(X
或Y
)。
有人可以解释一下RS='|'
awk 没有将其视为空字符串时发生了什么吗?
我也尝试过,RS='(|)'
但这完全是另一回事,我看到它将整个输入视为单个记录。
答案1
根据定义RS='|'
是一个字面意思|
。任何单个字符 RS 都被视为文字,以便在所有 awk 之间进行移植,否则您的脚本RS='|'
在 gawk 与 POSIX awk 中的行为会有所不同。因此,单个字符 RS 是文字,而作为 RS 的多字符字符串是正则表达式,如果 awk 版本支持它,否则它实际上只是字符串的第一个字符(因此RS='.'
始终是文字,.
而在某些情况RS='.x'
下,任何字符都后跟) x
aws 和其他的文字.
)。
顺便说一句,在任何其他正则表达式上下文中,单个字符|
对于 POSIX 来说都是未定义的行为,但许多工具会将其视为文字,对于正则表达式重复字符(如和 )|
也是如此。*
?
至于RS='(|)'
- 表示“null 或 null”,与“null”相同,您也可以将其写为()
.似乎所有字符都匹配,我不知道为什么不匹配。不同的工具似乎以不同的方式识别正则表达式:
$ printf 'foo\n' | sed -E 's/()/x/g'
xfxoxox
$ printf 'foo\n' | grep -Eo '()'
$
$ printf 'foo\n' | awk '{gsub(/()/,"x")} 1'
xfxoxox
$ printf 'foo\n' | awk -v RS='()' -v ORS='x\n' '1'
foox
我联系了 GNU Awk 开发人员(请参阅https://lists.gnu.org/archive/html/bug-gawk/2021-01/msg00003.html)并从中得出两件事:
- 不得使用与空字符串匹配的多字符正则表达式作为记录分隔符或字段分隔符。如果这样做,将被处理为 RS 或 FS 不存在,并且您最终将得到整个输入的单个记录(对于 RS)或整个记录的单个字段(对于 FS)。这将在未来版本的 gawk 手册中明确说明。
- gawk 5.1.0(也许也更早,我不知道)中有一个错误,当忽略上述语句时,会导致终止字符被消耗。现在已经为此编写了一个修复程序,并将在未来的 gawk 版本中发布。