Conversion de base BASH de décimal en hexadécimal

29

Dans Bash, comment fait-on une conversion de base de décimal en une autre base, en particulier hexadécimale. Il semble facile d'aller dans l'autre sens:

$ echo $((16#55))
85

Avec une recherche sur le Web, j'ai trouvé un script qui fait le calcul et la manipulation des caractères pour effectuer la conversion, et je pourrais l'utiliser comme fonction, mais j'aurais pensé que bash aurait déjà une conversion de base intégrée - le fait-il?

Dave Rove
la source
stackoverflow.com/questions/378829/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Réponses:

35

Avec bash(ou n'importe quel shell, à condition que la printfcommande soit disponible (une commande POSIX standard souvent construite dans les shells)):

printf '%x\n' 85

Avec zsh, vous pouvez aussi faire:

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

Cela fonctionne pour les bases de 2 à 36 (avec une 0-9a-zcasse insensible aux chiffres).

Avec ksh93, vous pouvez utiliser:

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

Ce qui fonctionne pour les bases de 2 à 64 (avec 0-9a-zA-Z@_comme chiffres).

Avec kshet zsh, il y a aussi:

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

Bien que cela soit limité aux bases jusqu'à 36 en ksh88, zsh et pdksh et 64 en ksh93.

Notez que tous ceux-ci sont limités à la taille des longentiers sur votre système ( intavec certains shells). Pour quelque chose de plus grand, vous pouvez utiliser bcou dc.

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

Avec des bases prises en charge allant de 2 à un certain nombre requis par POSIX pour être au moins aussi élevé que 99. Pour les bases supérieures à 16, les chiffres supérieurs à 9 sont représentés sous la forme de nombres décimaux séparés par des espaces et 0.

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

Ou même avec dc( bcutilisé pour être (et est toujours sur certains systèmes) un wrapper dc):

$ echo 30o123456p | dc
 04 17 05 06
Stéphane Chazelas
la source
Merci. Exactement ce que je cherchais. (Et d'une simplicité embarrassante.)
Dave Rove
Et si vous voulez faire une base arbitraire comme vous pouvez le spécifier avec #?
flarn2006
@ flarn2006. Avec les fonctions bashintégrées, vous pouvez entrer des nombres dans n'importe quelle base, mais pas en sortie dans une base autre que 8, 10 et 16. Pour d'autres bases, vous auriez besoin d'un autre shell comme zshou kshou use bc/dc.
Stéphane Chazelas
1
@ StéphaneChazelas Vraiment? C'est un peu bizarre. Il semble presque qu'ils étaient trop paresseux pour programmer une syntaxe pour cela ou quelque chose; il n'y a aucun moyen que l'idée de produire dans n'importe quelle base ne leur ait pas traversé l'esprit s'ils ont implémenté la saisie.
flarn2006
alias hex="printf '%x\n'"
mwfearnley
5

Utilisez printf:

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

Pour affecter la valeur à une variable, utilisez la substitution de commande:

$ x=$( printf "%x" 85 ) ; echo $x
55
Janis
la source
4
Ou, utilisez l' -voption pour le printf intégré:printf -v foo "%d" $((16#BEEF)); echo $foo
glenn jackman
@Glenn L'utilisation d'options non standard (comme -v) n'est pas nécessaire ici; Je l'éviterais.
Janis
3
-véviterait la fourche et le tuyau (en bash, pas ksh93 qui ne bifurquerait pas ici comme il printfest intégré). Notez que ce $((16#55))n'est pas standard non plus.
Stéphane Chazelas
@ StéphaneChazelas, attendez une minute. Voulez-vous dire que ksh93 ne bifurque pas x=$(some_builtin)?
glenn jackman
1
@glennjackman, oui, il ne fait que bifurquer pour exécuter des commandes externes.
Stéphane Chazelas
2

Utilisez la substitution d'expansion arithmétique intégrée présente dans tous les shells compatibles POSIX - qui est à peu près universelle de nos jours.

$ echo $((0xbc))
188

et

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

ATTENTION: en particulier dans le dernier exemple, l'expansion peut entraîner des résultats inattendus - les chiffres hexadécimaux dans la variable «hex» doivent former une constante hexadécimale légale, sinon des messages d'erreur potentiellement obscurs se produisent. Par exemple, si «hex» était «0xdead», l'expansion arithmétique deviendrait 0x0xdead, ce qui n'est pas interprétable comme une constante. Bien sûr, dans ce cas, l'expansion arithmétique $ (($ hex)) ferait l'affaire. Il est laissé comme exercice au lecteur de créer la correspondance de modèle de traitement de sous-chaîne simple qui supprimerait un préfixe «0x» facultatif.

Mark van der Pol
la source
4
Vous faites exactement la même chose que le PO dans son exemple; il cherche l' opération inverse .
Thomas Guyot-Sionnest
0

Vous pouvez utiliser la bibliothèque awk Velour :

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

Ou:

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