我正在尝试从网络流编写数据库脚本。网络流在经过大量 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 一起