【问题标题】:GAWK premature EOF with getline带有 getline 的 GAWK 过早的 EOF
【发布时间】:2016-01-21 17:40:31
【问题描述】:

这里是交易:我需要读取一个特定数量的字节,稍后将处理它。但是我遇到了一个奇怪的现象,我无法理解它。也许是其他人? :)

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

至少使用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/ 中。然后我需要做一些最后的处理步骤。上面的例子只是最基本的脚本,用来说明问题。

【问题讨论】:

  • 我现在没有办法对此进行测试,但我希望 awk 能够在不需要 getline 的情况下从 cmd-line 中获得文件列表。您是否尝试过使用多个文件的原始代码? pluse-uno 用于深入研究的问题。但是,是的,您的测试似乎应该可以工作,并且不清楚您丢失数据的原因。哦..您的数据中有\r\n 行结尾的机会吗?如果是这样,dos2unix file... | tr -d '\015' | ...。继续发帖,祝你好运。
  • 好吧,我正在做的是从stdin 读取数据,并将其放入/dev/shm 的临时文件中,然后再读取该文件并进行一些处理。 (数据应该来自网络nc)非常感谢,我正在尽我所能......;)
  • 嗯..您说“但是,我需要几个文件才能访问,..”。对于其他读者,您可能想澄清您的echo abcedfg | awk .. 反映了您真正想要如何处理这个问题。祝你好运!
  • 为了好玩,可以尝试在while 循环之后放置一个print "" --- 以防有一些挥之不去的输出由于某种原因没有被刷新。
  • I'll need several files, to be accessed, so I am forced to use getline - 该声明完全不清楚,因为 awk 在读取多个文件时不需要 getline,一旦您告诉我们您是从 stdin 而不是从任何文件中读取,它就变得更加不清晰.请编辑您的问题以明确说明 awk 从何处获取输入,如果您认为需要使用 getline,请明确说明为什么会这样。您可能还想阅读awk.info/?tip/getline

标签: bash awk gawk


【解决方案1】:

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

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


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

head -c $count

dd bs=$count count=1

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

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

【讨论】:

  • 好吧,我确实遇到了一个错误。我不是在问,你是怎么知道这件事的。 :) 你是对的,awk 可能不是正确的工具。但问题是,我必须处理基于行的数据,其中偶尔会出现八位字节块,因此尝试摆脱这种情况是相当诱人的。但我没有。 :)
  • @Dan:我不知道,但我证实它发生在 v4.0 而不是 v4.1,因为我两者都有。然后我在 buglist 中搜索了 getline,这很容易找到。祝项目顺利。
【解决方案2】:

幸运的是,使用 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

【讨论】:

  • 如果getline 失败,它将进入无限循环。见awk.info/?tip/getline
  • 只是为了记录,根据official doc它不应该:[...] The getline command returns 1 if it finds a record and 0 if it encounters the end of the file. [...]
  • @Dan:你遗漏了下一句:“如果有一些错误...... getline 返回 -1”。 -1 和 1 一样,为真。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-21
  • 1970-01-01
  • 1970-01-01
  • 2012-09-14
  • 1970-01-01
  • 2012-01-03
  • 2019-11-13
相关资源
最近更新 更多