GAWK 过早的 EOF 与 getline

GAWK premature EOF with getline

事情是这样的:我需要读取特定数量的字节,这将在稍后处理。不过,我遇到了一个奇怪的现象,我无法理解它。也许是别人? :)

注意:以下代码示例是精简版,只是为了展示效果!

一种方法,至少对于 gawk,是将 RS 设置为包罗万象的 regex,然后使用 RT 看看,匹配到了什么:

RS="[\x00-\xFF]"

然后,非常简单地使用以下 awk-script:

BEGIN {
  ORS=""
  OFS=""
  RS="[\x00-\xFF]"
}
{
  print RT
}

这工作正常:

$ echo "abcdef" | awk -f bug.awk
abcdef

但是,我需要访问几个文件,所以我不得不使用 getline:

BEGIN {
  ORS=""
  OFS=""
  RS="[\x00-\xFF]"

  while (getline)
  {
    print RT
  }
}

貌似相当于上面的,但是当运行它的时候,有一个令人讨厌的惊喜:

$ echo "abcdef" | awk -f bug.awk
abc

这意味着,出于某种原因,getline 遇到 EOF 条件 提前 3 个字节。那么,我是不是错过了什么,我应该了解 bash/Linux 缓冲的内部结构,还是我发现了一个可怕的 bug

仅作记录:我在 Ubuntu 14.04 LTS (Linux 3.13.0/36)

上使用 GNU Awk 4.0.1

伙计们,有什么建议吗?

更新:我正在使用 getline,因为我之前已经读取并预处理了文件,并存储在文件 /dev/shm/ 中。然后我需要做一些最后的处理步骤。上面的例子只是最低限度的脚本,用来说明问题。

幸运的是,使用 GNU Awk 4.1.3(在 Mac 上),带有 getline 的程序按预期运行:

echo "abcdef" | gawk 'BEGIN{ORS="";OFS="";RS="[\x00-\xFF]";
  while (getline) {print RT}}'
abcdef
$ gawk --version
GNU Awk 4.1.3, API: 1.1

这似乎是报告的错误 here 的表现,它(如果我理解正确的话)具有在接近输入结束时过早终止 getline 的效果,而不是比输入结束时。

错误修复似乎已于 2014 年 May 9 and May 10 提交,因此如果您可以升级到 4.1 版,它应该可以解决问题。


如果您需要做的只是读取指定数量的字节,我建议 awk 不是理想的工具,无论是否存在错误。相反,您可以考虑使用以下两个标准实用程序之一,它们可以更有效地完成工作:

head -c $count

dd bs=$count count=1

使用 dd 如果 stdin/stdout 不合适,您可以明确设置输入文件 (if=PATH) 和输出文件 (of=PATH)。使用 head 您可以将输入文件指定为位置参数,但输出始终转到标准输出。

有关详细信息,请参阅 man head and man dd