p=n/1000
printf "%s",arr[p];
尽管我已经检查了 的值,但这并没有打印任何内容p
。
出来的效果还不错。
我也尝试过以这种方式打印元素:
printf "%s",arr[7];
这个有效。
答案1
如中所述GNU Awk 用户指南 8.2 使用数字为数组添加下标
关于数组需要记住的一个重要方面是数组下标始终是字符串。当数字值用作下标时,在用于下标之前会先将其转换为字符串值
如果n
是7432
那么n/1000
是7.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
7432/1000 不是整数。awk
内部使用 C 编译器的double
类型来表示浮点数。在 x86 上的 GNU 系统上,这是 IEEE 754 二进制 64。
就像 1/3 不能用十进制表示一样(即 0.33333 有无数个 3),7432/1000 也不能用二进制表示。该数字awk
的double
近似值是一个二进制数,转换回十进制后为(精确)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
不可移植:gawk
mawk
$ 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