BASH Basisumrechnung von dezimal nach hex

29

Wie wandelt man in Bash eine Basis von einer Dezimalzahl in eine andere Basis um, insbesondere hexadezimal. Es scheint einfach, den anderen Weg zu gehen:

$ echo $((16#55))
85

Bei einer Websuche habe ich ein Skript gefunden, das die Mathematik- und Zeichenmanipulation für die Konvertierung ausführt, und das könnte ich als Funktion verwenden, aber ich hätte gedacht, dass bash bereits eine integrierte Basiskonvertierung hat - macht es?

Dave Rove
quelle

Antworten:

35

Mit bash(oder einer beliebigen Shell, sofern der printfBefehl verfügbar ist (ein POSIX-Standardbefehl, der häufig in die Shells integriert ist):

printf '%x\n' 85

Mit zshkönnen Sie auch Folgendes tun:

dec=85
hex=$(([##16]dec))

Das funktioniert für Basen von 2 bis 36 (wobei die 0-9a-zGroß- und Kleinschreibung keine Rolle spielt).

Mit ksh93können Sie Folgendes verwenden:

dec=85
base54=$(printf %..54 "$dec")

Welches funktioniert für Basen von 2 bis 64 (mit 0-9a-zA-Z@_als die Ziffern).

Mit kshund zshgibt es auch:

$ typeset -i34 x=123; echo "$x"
34#3l

Dies ist jedoch auf Basen bis zu 36 in ksh88, zsh und pdksh und 64 in ksh93 beschränkt.

Beachten Sie, dass alle diese Werte auf die Größe der longGanzzahlen Ihres Systems beschränkt sind ( intmit einigen Shells). Für etwas größeres können Sie bcoder verwenden dc.

$ echo 'obase=16; 9999999999999999999999' | bc
21E19E0C9BAB23FFFFF
$ echo '16o 9999999999999999999999 p' | dc
21E19E0C9BAB23FFFFF

Bei unterstützten Basen von 2 bis zu einer von POSIX geforderten Zahl von mindestens 99 werden Ziffern größer als 9 als durch Leerzeichen getrennte, mit 0 aufgefüllte Dezimalzahlen dargestellt.

$ echo 'obase=30; 123456' | bc
 04 17 05 06

Oder dasselbe mit dc(war bcfrüher (und ist auf einigen Systemen immer noch) ein Wrapper dc):

$ echo 30o123456p | dc
 04 17 05 06
Stéphane Chazelas
quelle
Vielen Dank. Genau das, wonach ich gesucht habe. (Und peinlich einfach.)
Dave Rove
Was ist, wenn Sie eine beliebige Basis erstellen möchten, wie Sie sie angeben können #?
Flarn2006
@ flarn2006. Mit bashbuiltins können Sie Eingangsnummern in jeder Basis, aber nicht ausgegeben in irgendeiner anderen Base als 8, 10 und 16. Für andere Basen, müssten Sie eine andere Shell wie zshoder kshoder Verwendung bc/dc.
Stéphane Chazelas
1
@ StéphaneChazelas Wirklich? Das ist irgendwie komisch. Es scheint fast so, als wären sie zu faul, um eine Syntax dafür oder so etwas zu programmieren. Die Idee, in irgendeiner Basis auszugeben, kam ihnen auf keinen Fall in den Sinn, wenn sie Eingaben implementierten.
Flarn2006
alias hex="printf '%x\n'"
Mwfearnley
5

Verwenden Sie printf:

$ printf "%d %x\n" $((16#55)) $((10#85))
85 55

Um den Wert einer Variablen zuzuweisen, verwenden Sie die Befehlssubstitution:

$ x=$( printf "%x" 85 ) ; echo $x
55
Janis
quelle
4
Oder verwenden Sie die -vOption für den eingebauten Ausdruck:printf -v foo "%d" $((16#BEEF)); echo $foo
Glenn Jackman
@Glenn Hier ist es nicht erforderlich, nicht standardmäßige Optionen (wie -v) zu verwenden. Ich würde es vermeiden.
Janis
3
-vwürde die Gabel und das Rohr vermeiden (in Bash, nicht ksh93, das hier nicht printfgabelt, wie es eingebaut ist). Beachten Sie, dass dies auch $((16#55))nicht Standard ist.
Stéphane Chazelas
@ StéphaneChazelas, warte eine Minute. Wollen Sie damit sagen, dass ksh93 nicht nachgabelt x=$(some_builtin)?
Glenn Jackman
1
@glennjackman, ja, es werden nur externe Befehle abgefragt.
Stéphane Chazelas
2

Verwenden Sie die in allen POSIX-kompatiblen Shells integrierte Arithmetic Expansion-Substitution, die heutzutage praktisch universell ist.

$ echo $((0xbc))
188

und

$ hex=dead
$ dec=$((0x$hex))
$ echo $dec
57005

VORSICHT: Insbesondere im letzten Beispiel kann die Erweiterung zu unerwarteten Ergebnissen führen. Die Hexadezimalziffern in der Variablen 'hex' müssen eine zulässige Hexadezimalkonstante bilden, da sonst möglicherweise undurchsichtige Fehlermeldungen auftreten. Beispiel: Wenn 'hex' '0xdead' wäre, würde die arithmetische Erweiterung zu 0x0xdead, was nicht als Konstante interpretiert werden kann. In diesem Fall würde natürlich die arithmetische Erweiterung $ (($ hex)) den Trick machen. Es ist eine Übung für den Leser, den einfachen Mustervergleich für die Teilzeichenfolgenverarbeitung zu erstellen, bei dem das optionale Präfix '0x' entfernt wird.

Mark van der Pol
quelle
4
Sie tun genau dasselbe, was der OP in seinem Beispiel getan hat. er sucht den umgekehrten Vorgang.
Thomas Guyot-Sionnest
0

Sie können die awk Velour-Bibliothek verwenden :

$ velour -n 'print n_baseconv(15, 10, 16)'
F

Oder:

$ velour -n 'print n_baseconv(ARGV[1], 10, 16)' 15
F
Steven Penny
quelle