【问题标题】:How to print float value from binary file in shell?如何在 shell 中从二进制文件中打印浮点值?
【发布时间】:2016-04-22 10:43:03
【问题描述】:

我有一个包含双浮点(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字节浮点数也一样,只是把&lt;d改成&lt;f(后面提到float.bin)。

如何使用更简洁的方式(不使用 Python)从 shell 脚本中打印该值?使用内置工具(例如printf)或广泛使用的外部工具(例如xxddcbcodhexdump等)。


例如要打印十进制值,我可以使用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 converter0x3dfbe76d0.123 相同,因此十六进制值是相反的(xxd 实际给出的值)。

【问题讨论】:

    标签: shell command-line floating-point binary-data xxd


    【解决方案1】:

    这不使用 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 用于长双精度),简而言之-tfD 可以替换为 -e-F。要只打印不带地址的值,可以指定-A n

    【讨论】:

    • +1:听起来像odcoreutils 的一部分)甚至更短,这很好用,谢谢。这是精简版:od -tfD file.bin | awk '{print $2}' | xargs.
    【解决方案2】:
    od -f <filename>
    

    这会将您的文件转储为浮点数。

    od 是一个标准的 Linux 工具,也是我使用的。手册页内容如下:

    od - 以八进制和其他格式转储文件

    【讨论】:

    • od -t fD &lt;filename&gt; 双打
    【解决方案3】:

    作为单行者

    echo -n "000000000000f03f" | while read -N2 code; do printf "\x$code"; done | od -t f8
    

    【讨论】:

    • 它应该产生:0000000 1?
    • 是的 3ff0000000000000 in little endian 是我答案的回声体,该值是实际值 1.0e0 的 IEEE754 二进制表示。它是像任何 x86 一样的小端机器的示例
    【解决方案4】:

    您可能希望考虑一些提到的工具,例如 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?

    【讨论】:

    • 如果您已经采用浮点格式,但您缺少从十六进制格式表示的转换。因此从3dfbe76d 转换为0.123(如果是4 字节浮点数)。
    猜你喜欢
    • 2018-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多