AWK END 行为是否将最后一行加载到手册页的 $0 中?

AWK END 行为是否将最后一行加载到手册页的 $0 中?

我读另一个答案描述了如何使用AWK查看最后一行输出:

$ seq 42 | awk 'END { print }'
42

所以看起来当END块运行时,最后一行被加载到$0.

这让我感到惊讶,因为第一行没有加载到BEGIN块中:

$ seq 42 | awk 'BEGIN { print }'
#=> blank
  • 此行为文档在任何地方吗? (我通过搜索手册页但没有找到任何东西)

答案1

BEGIN块在处理任何输入之前运行,因此$0尚未初始化。

END块不会对 执行任何操作$0,从而保留其最后的值。在 AWK 脚本中,这只是读取的最后一行,因为 AWK 逐行读取其所有输入,执行通常的字段分割处理(分配$0等),但永远找不到匹配的块;但例如

seq 42 | awk '{ $0 = "21" } END { print }'

输出 21,而不是 42,因此不是“当END块运行时加载最后一行$0”的情况。

这没有记录在gawk(1)联机帮助页,但它记录在mawk(1)(显然对于 AWK 的实现):

类似地,在进入操作时END$0、 、 和 字段NF的值与最后一条记录相比保持不变。

GNU AWK 手册确实提及这种行为

事实上,所有 BWK awkmawk、 和gawk都保留 的值以供在规则$0中使用。END

“BWK awk” 是 Brian Kernighanawk“一个真实的awk;它在 2005 年实施了这种行为,如其FIXES文件中所述:

2005 年 4 月 24 日:进行修改lib.c,以便将$0et al 的值保留在 END 块中,显然是按照 posix 的要求。感谢 havard eidnes 提供的报告和代码。

这种变化可见于“一个真实的awk”历史。最新版本的 BWK 的awk行为方式与 GNU AWK 相同:

$ echo three fields here | ./awk '{ $0 = "one" } END { print $0 " " NF }'
one 1
$ echo three fields here | ./awk 'END { $0 = "one"; print $0 " " NF }'
one 1

答案2

根据GNU awk 手册,有点不清楚$0END 规则中应包含什么内容。 POSIX 要求NF “应保留[其]价值”(*),但没有提及$0.

最有可能的是由于疏忽,该标准并没有说它$0也被保留,尽管从逻辑上讲人们会认为它应该被保留。事实上,所有 BWK awk、mawk 和 gawk 都保留 的值$0以供在END规则中使用。但请注意,一些其他实现和许多旧版本的 Unix awk 不支持。

从某种意义上说,我认为这种行为是合乎逻辑的。如有必要,离开$0END块可以轻松访问最后一条记录。第一条记录很容易访问,NR == 1 {...}因此不需要特殊的关键字。另一方面, BEGIN在加载第一条记录之前执行块允许设置FSRS及时让它们对于第一条记录是活动的。

(* 无论这意味着什么,请参阅评论。)

相关内容