如何在 gawk 中将一列十六进制转换为十进制,gawk 中的 strtonum 给出错误结果

如何在 gawk 中将一列十六进制转换为十进制,gawk 中的 strtonum 给出错误结果

我正在尝试从网络流编写数据库脚本。网络流在经过大量 sed 处理后会删除一个三列文件,该文件类似于 file.db

123.123.123.123,计算机名称,110000103e21cc4

123.123.123.124,计算机2,11000010416200f

123.123.123.1,计算机3,110000106eb3f43

我尝试使用这个 gawk 命令,但没有效果

gawk 'BEGIN {FS=OFS=","} {print $1,$2,strtonum("0x"$3)}' file.db

上面的输出如下所示

123.123.123.123,计算机名称,76561198025415874

123.123.123.124,计算机2,76561198028824592

123.123.123.1,计算机3,76561198076346171

然而输出应该转换为这个

123.123.123.123,计算机名称,76561198025415876

123.123.123.124,计算机2,76561198028824591

123.123.123.1,计算机3,76561198076346179

输出总是有少量偏差,所以我假设系统上的一些库不正确...顺便说一句,这是一个正在运行的嵌入式系统,我知道它可以转换,因为我用 bc、printf 等完成了它

我怎样才能做到这一点

答案1

内部gawk将转换后的值存储为双精度浮点数,因此小的差异只是继承于任何浮点值的舍入误差。要获得准确的结果,gawk需要将数字处理外包给支持任意精度数字的其他命令,例如bc

但是,使用当前gawk语法无法在 gawk 中进行复杂的 shell 命令行解析,因此首先需要一个 shell 脚本助手。我们将其命名为bc.sh

#!/bin/bash
echo -e "ibase=16\n$1" | bc -q

此脚本将ibase=16和第一个参数(十六进制数)输入到bc,以便bc输出相应的十进制数。然后gawk可以这样调用:

gawk 'BEGIN {FS=OFS=","} { "./bc.sh " toupper($3) | getline b; print $1,$2,b}' file.db

这告诉gawk使用大写的 $3 (bc不支持小写的十六进制值)调用 shell 脚本,将结果存储到b变量中,并一次性打印所有参数。

请注意,./bc.sh双引号内必须附加一些空格,否则它将尝试执行不存在的文件,例如./bc.sh110000103E21CC4

答案2

我回顾这件事,我最终这样做的方式是

制作一个 bash 脚本,例如所谓的 convert12345678.sh

#!/opt/bin/bash
(echo -e "ibase=16\nobase=0A" ; echo $1 | tr 'a-z' 'A-Z') | bc | tr "\n" " " | sed 's/\ //g'

然后在 gawk 中,我需要说的就像在 op 中那样(从那时起,我对该程序进行了大量修改)是这样的,我通过管道传输了这个程序,但我将从一个文件中进行演示

gawk -F, '{printf("%s,%s,",$1,$2)};{system("/files/convert12345678 "$3)};{printf("\n")}' file.db

我这样做是为了删除 bash 脚本中的新行,因为老实说,我之后会移动它,也就是脚本执行的位置,这样我就不会在转换后立即将换行符插入到输出中,除非我希望它与 printf 一起

相关内容