2016-04-22 13 views
2

I Binärdatei bestehend Doppelschwimmer (8 Byte) oder einfach nur schwimmen (4 Byte) Wert habe, die in der folgenden Art und Weise erzeugt wurden:Wie float Wert aus Binärdatei in der Shell zu drucken?

$ 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..|.? 

, das ich es wieder aus Python über drucken konnte:

$ python -c $'from struct import unpack\nwith open("file.bin", "rb") as f: print(unpack("<d", f.read(8)))' 
(0.123,) 

Das gleiche für 4-Byte-Float, ändern Sie einfach <d in <f (später als float.bin erwähnt).

Wie drucke ich diesen Wert aus dem Shell-Skript mit sauberer Weise (ohne Python)? Entweder unter Verwendung von eingebauten Werkzeugen (z. B. printf) oder weit verbreiteten externen Werkzeugen (z. B. xxd, dc, bc, od, hexdump usw.).


Zum Beispiel Dezimalwerte zu drucken, kann ich xxd (Teil von VIM) verwenden, z.B. in Bash:

  • den Wert des ersten Bytes erhalten:

    $ echo $((16#$(xxd -ps -s0 -l1 file.bin))) 
    176 
    

    Für 2. und her Bytes, erhöhen -s.

  • erhalten Dezimalwert aus allen 8 Bytes:

    $ echo $((16#$(xxd -ps -s0 -l8 file.bin))) 
    -5732404399725297857 
    

Allerdings Ich mag würde Original Floating-Wert (0.123) auf Unix-Familie System drucken. Idealerweise mit einem Einzeiler (um es als Teil des Skripts einfach zu halten), also kann ich es als Textvariable zuweisen oder den Wert auf dem Bildschirm ausgeben.


Ich habe versucht, printf zu verwenden (auf der 4-Byte-Float-Zahl, um es einfacher zu machen), aber es hat nicht wie erwartet:

$ 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 

wo nach dieser on-line converter, 0x3dfbe76d ist das gleiche wie 0.123, also sind die Hex-Werte umgekehrt (was xxd tatsächlich gibt).

Antwort

6

Diese nicht Python nicht verwendet und ist ein weit verbreitetes externes Tool, Perl.

perl -e "print pack('d>',0.123)" > file.bin 

perl -e "print unpack('d>',<>)" < file.bin 
0.123 

Oder können Sie GNU od Dienstprogramm, zum Beispiel verwenden:

od -tfD file.bin 
0000000     0.123 
0000010 

Wo -t Parameter das Ausgabeformat für Gleitkommazahlen (f), gefolgt von optionaler Größe Spezifizierer (F für Schwimmer gibt, D für Doppel oder L für lange Doppel), kurz -tfD kann durch -e oder -F ersetzt werden. Um nur Werte ohne Adresse zu drucken, kann -A n angegeben werden.

+0

+1: Klingt wie 'od' (Teil von' coreutils') ist noch kürzer, das funktioniert super, danke. Hier ist die getrimmte Version: 'od -tfD file.bin | awk '{print $ 2}' | Xargs'. – kenorb

0

Vielleicht möchten Sie einige der genannten Werkzeuge berücksichtigen wie bc, die in arithmetischen Operationen und Vergleichen verwendet werden können - zB:

#!/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" ; 

Zusätzliche Formatierung für nahe stehende Zahlen und Typen wie Null erforderlich sein kann; wie in einigen anderen Nachrichten adressiert zB: How to show zero before decimal point in bc?

+0

Großartig, wenn Sie sich bereits im Float-Format haben, aber Sie fehlt Umwandlung von Hex-Format Darstellung. Also Umwandlung von "3dfbe76d" in "0.123" (im Falle von 4-Byte Float). – kenorb

1
od -f <filename> 

Das wird Ihre Datei als Floats ablegen.

od ist ein Standard-Linux-Tool, und es ist was ich verwende. Die Manpage liest:

od - Dump-Dateien in Oktal und andere Formate