为什么 GNU awk 实现限制在实践中似乎不起作用?

为什么 GNU awk 实现限制在实践中似乎不起作用?

这一页提到 GNU awk 实现限制时提到字段大小和文字字符串大小的限制是MAX_INT

但是,当我将长字符串文字声明为变量并尝试使用函数查找其长度时length,当字符串长度超过 308 个字符时,该函数似乎会中断。下面的例子:

BEGIN {
  avar=1234... #309 characters
  print length(avar) #prints 3 but prints right length when length < 309
} 

但是,以下命令行适用于 1000 个字符:

echo 1234... | awk '{print length($1)}' #tested and works for 1000 characters

我使用的是 CentOS 7 系统,我的 awk 版本是 4.0.2。

关于为什么会出现这种差异有什么建议吗?

答案1

您尝试做的事情可能会更容易重复:

awk 'BEGIN {
  avar='"$(printf '%0200d' 0)"' #309 characters
  print avar,length(avar) #prints 3 but prints right length when length < 309
} '

其中打印0 1,这意味着 200 个零的整个列表被 awk 转换为一个单个0,这似乎暗示这就是价值写有 200 个零的整数。

让我们给它一些其他值(8 后跟 200 个零):

➤ awk 'BEGIN {
  avar='"$(printf '8%0200d' 0)"' #309 characters
  print avar,length(avar) #prints 3 but prints right length when length < 309
} '
799999999999999975786497770008289327579602620364018901185934007602774787484432604273570707237650014944220099327791059265457085874946227877115080328377919022968188728534319854489454506449337030839107584 201

这是 的浮点近似值8e200。这很容易通过以下方式确认:

➤ awk 'BEGIN {
  avar='"$(printf '8%0200d' 0)"' #309 characters
  print avar,length(avar) #prints 3 but prints right length when length < 309
  printf "%15e\n",avar
} '
799999999999999975786497770008289327579602620364018901185934007602774787484432604273570707237650014944220099327791059265457085874946227877115080328377919022968188728534319854489454506449337030839107584 201
  8.000000e+200

因此,代码赋值 ( ) 中给出的数字avar=被(正确地)处理为数值。双浮点数最多只能存储 308 的指数(不包括次正规数)。因此,超过 308 位的数值不能转换为浮点数。

➤ ➤ awk 'BEGIN {
  avar='"$(printf '8%0308d' 0)"' #309 characters
  print avar,length(avar) #prints 3 but prints right length when length < 309
  printf "%15e\n",avar
} '
inf 3
            inf

不过,作为字符串,用双引号 ( avar="...") 括起来是没有问题的。

➤ awk 'BEGIN {
  avar="'"$(printf '8%0600d' 0)"'" #309 characters
  print avar,length(avar) #prints 3 but prints right length when length < 309
} '
8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 601

在数据来自管道(或文件)的情况下,数据被假定为字符串(除非强制转换为具有data + 0或类似的数字),并且其长度是其字符数。

$ printf '8%02000d0\n' 0 | awk '{print length($1)}'
2002

相关内容