awk中打​​印数组元素的问题

awk中打​​印数组元素的问题
p=n/1000
printf "%s",arr[p];

尽管我已经检查了 的值,但这并没有打印任何内容p
出来的效果还不错。
我也尝试过以这种方式打印元素:

printf "%s",arr[7];

这个有效。

答案1

如中所述GNU Awk 用户指南 8.2 使用数字为数组添加下标

关于数组需要记住的一个重要方面是数组下标始终是字符串。当数字值用作下标时,在用于下标之前会先将其转换为字符串值

如果n7432那么n/10007.432- 默认情况下不会四舍五入。所以

$ awk -vn=7432 'BEGIN{arr[7] = "seven"; arr["7.432"] = "foo"; p = n/1000; print p, arr[p]}'
7.432 foo

然而

$ awk -vn=7432 'BEGIN{arr[7] = "seven"; arr["7.432"] = "foo"; p = int(n/1000); print p, arr[p]}'
7 seven

答案2

的补充@steeldriver 的好答案

7432/1000 不是整数。awk内部使用 C 编译器的double类型来表示浮点数。在 x86 上的 GNU 系统上,这是 IEEE 754 二进制 64。

就像 1/3 不能用十进制表示一样(即 0.33333 有无数个 3),7432/1000 也不能用二进制表示。该数字awkdouble近似值是一个二进制数,转换回十进制后为(精确)7.4320000000000003836930773104541003704071044921875。

现在,在 中awk,当非整数转换为字符串表示形式时,二进制内部表示形式的确切值不会完全保留。考虑到上面的大多数数字实际上代表了一个错误,这不会很有用。相反,使用CONVFMT包含printf类似格式的特殊参数将浮点数转换回字符串

默认情况下CONVFMT%.6g.这意味着转换为字符串时仅保留 6 位十进制精度。可以将其更改为任何内容,但请注意,只有浮点说明符(%e, %f, %g...)是可移植的。

当这些数字用作需要字符串的函数或运算符的参数时,它们会转换为字符串,例如substr()、串联...

正如 @steeldriver 所说,其中之一是关联数组的键,这些数组始终是字符串。

所以做a[7432/1000] = x其实就是做a[sprintf(CONVFMT, 7432/1000)]。如果使用默认值CONVFMT,则变为a["0.7432"] = x,但如果CONVFMT更改为%.1e,则为a["7.0e-01"] = x,或者如果为%.25g,则为a["7.4320000000000003837"] = x

所以在这里你实际上可以使用来CONVFMT=%.0f确保数组的键是整数:

$ awk -v CONVFMT=%.0f 'BEGIN{a[7432/1000] = 1; print a[7]}'
1

但请注意,%.0f四舍五入到最接近的整数,同时%d截断小数部分。尽管可以与and一起使用,但使用CONVFMT=%d不可移植:gawkmawk

$ gawk -v CONVFMT=%d 'BEGIN{a[7564/1000] = 1; print a[7]}'
1
$ gawk -v CONVFMT=%.0f 'BEGIN{a[7564/1000] = 1; print a[8]}'
1

¹ 不包括使用print以下方法转换的浮点参数OFMT

相关内容