如何从 shell 中的二进制文件打印浮点值?
How to print float value from binary file in shell?
我的二进制文件包含双浮点数(8 字节)或仅浮点数(4 字节)值,它是通过以下方式生成的:
$ python -c $'from struct import pack\nwith open("file.bin", "wb") as f: f.write(pack("<d", 0.123))'
$ xxd file.bin
00000000: b072 6891 ed7c bf3f .rh..|.?
我可以通过以下方式从 Python 打印回来:
$ python -c $'from struct import unpack\nwith open("file.bin", "rb") as f: print(unpack("<d", f.read(8)))'
(0.123,)
4字节的float也一样,把<d
改成<f
即可(后面会提到float.bin
)。
如何使用更简洁的方式(不使用 Python)从 shell 脚本打印该值?使用内置工具(例如 printf
),或广泛使用的外部工具(例如 xxd
、dc
、bc
、od
、hexdump
, 等等).
例如要打印十进制值,我可以使用 xxd
(Vim 的一部分),例如在 Bash:
获取第一个字节的值:
$ echo $((16#$(xxd -ps -s0 -l1 file.bin)))
176
对于第二个和第四个字节,增加-s
。
从所有 8 个字节中获取十进制值:
$ echo $((16#$(xxd -ps -s0 -l8 file.bin)))
-5732404399725297857
不过我想在 Unix 系列系统上打印原始浮点值 (0.123
)。
理想情况下使用一些单行代码(作为脚本的一部分保持简单),这样我就可以将它分配给文本变量或在屏幕上打印该值。
我尝试使用 printf
(在 4 字节浮点数上以使其更简单),但它没有按预期工作:
$ xxd -p float.bin
6de7fb3d
$ printf "%.4f\n" 0x.$(xxd -p float.bin)
0.4293
$ printf "%.4f\n" 0x3dfbe76d
1039918957.0000
$ printf "%.4e\n" 0x3dfbe76d
1.0399e+09
根据此 on-line converter,0x3dfbe76d
与 0.123
相同,因此十六进制值是相反的(xxd
实际给出的值)。
您可能希望考虑一些提到的工具,例如 bc
,它们可用于算术运算和比较 - 例如:
#!/bin/bash
A=1.3141592653581 # variable 1
B=1.3141592653589 # variable 2
if (( `echo $A"<"$B | bc` )) ; then printf "$A is: < $B\n" ; else printf "$B is: < $A\n" ; fi ;
C=$(echo "$A+$B" | bc)
printf "C == $C\n" ;
可能需要对相关数字和类型(例如零)进行其他格式设置;如其他一些帖子中所述,例如:
How to show zero before decimal point in bc?
这不使用 Python 而是一个广泛使用的外部工具,Perl.
perl -e "print pack('d>',0.123)" > file.bin
perl -e "print unpack('d>',<>)" < file.bin
0.123
或者您可以使用 GNU od
实用程序,例如:
od -tfD file.bin
0000000 0.123
0000010
其中 -t
参数指定浮点数 (f
) 的输出格式,后跟可选的大小说明符(F
表示浮点数,D
表示双精度或L
for long double), 简而言之 -tfD
可以用 -e
或 -F
代替。要仅打印没有地址的值,可以指定 -A n
。
od -f <filename>
这会将您的文件转储为浮点数。
od
是标准的 Linux 工具,也是我使用的工具。联机帮助页显示:
od - dump files in octal and other formats
作为单行者
echo -n "000000000000f03f" | while read -N2 code; do printf "\x$code"; done | od -t f8
我的二进制文件包含双浮点数(8 字节)或仅浮点数(4 字节)值,它是通过以下方式生成的:
$ python -c $'from struct import pack\nwith open("file.bin", "wb") as f: f.write(pack("<d", 0.123))'
$ xxd file.bin
00000000: b072 6891 ed7c bf3f .rh..|.?
我可以通过以下方式从 Python 打印回来:
$ python -c $'from struct import unpack\nwith open("file.bin", "rb") as f: print(unpack("<d", f.read(8)))'
(0.123,)
4字节的float也一样,把<d
改成<f
即可(后面会提到float.bin
)。
如何使用更简洁的方式(不使用 Python)从 shell 脚本打印该值?使用内置工具(例如 printf
),或广泛使用的外部工具(例如 xxd
、dc
、bc
、od
、hexdump
, 等等).
例如要打印十进制值,我可以使用 xxd
(Vim 的一部分),例如在 Bash:
获取第一个字节的值:
$ echo $((16#$(xxd -ps -s0 -l1 file.bin))) 176
对于第二个和第四个字节,增加
-s
。从所有 8 个字节中获取十进制值:
$ echo $((16#$(xxd -ps -s0 -l8 file.bin))) -5732404399725297857
不过我想在 Unix 系列系统上打印原始浮点值 (0.123
)。
理想情况下使用一些单行代码(作为脚本的一部分保持简单),这样我就可以将它分配给文本变量或在屏幕上打印该值。
我尝试使用 printf
(在 4 字节浮点数上以使其更简单),但它没有按预期工作:
$ xxd -p float.bin
6de7fb3d
$ printf "%.4f\n" 0x.$(xxd -p float.bin)
0.4293
$ printf "%.4f\n" 0x3dfbe76d
1039918957.0000
$ printf "%.4e\n" 0x3dfbe76d
1.0399e+09
根据此 on-line converter,0x3dfbe76d
与 0.123
相同,因此十六进制值是相反的(xxd
实际给出的值)。
您可能希望考虑一些提到的工具,例如 bc
,它们可用于算术运算和比较 - 例如:
#!/bin/bash
A=1.3141592653581 # variable 1
B=1.3141592653589 # variable 2
if (( `echo $A"<"$B | bc` )) ; then printf "$A is: < $B\n" ; else printf "$B is: < $A\n" ; fi ;
C=$(echo "$A+$B" | bc)
printf "C == $C\n" ;
可能需要对相关数字和类型(例如零)进行其他格式设置;如其他一些帖子中所述,例如: How to show zero before decimal point in bc?
这不使用 Python 而是一个广泛使用的外部工具,Perl.
perl -e "print pack('d>',0.123)" > file.bin
perl -e "print unpack('d>',<>)" < file.bin
0.123
或者您可以使用 GNU od
实用程序,例如:
od -tfD file.bin
0000000 0.123
0000010
其中 -t
参数指定浮点数 (f
) 的输出格式,后跟可选的大小说明符(F
表示浮点数,D
表示双精度或L
for long double), 简而言之 -tfD
可以用 -e
或 -F
代替。要仅打印没有地址的值,可以指定 -A n
。
od -f <filename>
这会将您的文件转储为浮点数。
od
是标准的 Linux 工具,也是我使用的工具。联机帮助页显示:
od - dump files in octal and other formats
作为单行者
echo -n "000000000000f03f" | while read -N2 code; do printf "\x$code"; done | od -t f8