De hexadecimal a decimal en el script de shell

126

¿Alguien puede ayudarme a convertir un número hexadecimal a un número decimal en un script de shell?

Por ejemplo, quiero convertir el número hexadecimal bfca3000a decimal usando un script de shell. Básicamente quiero la diferencia de dos números hexadecimales.

Mi código es:

var3=`echo "ibase=16; $var1" | bc`
var4=`echo "ibase=16; $var2" | bc`
var5=$(($var4-$var3))               # [Line 48]

Al ejecutar, me sale este error:

Line 48: -: syntax error: operand expected (error token is "-")
VenkateshJN
fuente
Al revés: stackoverflow.com/questions/378829/… . Esencialmente las mismas herramientas. Y el posible sitio de cruz duplicado de: superuser.com/questions/226163/...
Ciro Santilli郝海东冠状病六四事件法轮功

Respuestas:

314

Para convertir de hexadecimal a decimal, hay muchas formas de hacerlo en el shell o con un programa externo:

Con :

$ echo $((16#FF))
255

con :

$ echo "ibase=16; FF" | bc
255

con :

$ perl -le 'print hex("FF");'
255

con :

$ printf "%d\n" 0xFF
255

con :

$ python -c 'print(int("FF", 16))'
255

con :

$ ruby -e 'p "FF".to_i(16)'
255

con :

$ nodejs <<< "console.log(parseInt('FF', 16))"
255

con :

$ rhino<<EOF
print(parseInt('FF', 16))
EOF
...
255

con :

$ groovy -e 'println Integer.parseInt("FF",16)'
255
Gilles Quenot
fuente
1
Qué ? bc es un lenguaje de calculadora de precisión arbitraria : un comando externo.
Gilles Quenot
10
Y entonces ? Este es exactamente el propósito de mis 4 comandos antes de modificar el sentido de su pregunta.
Gilles Quenot
2
¿La printfsolución es POSIX? Si es así, es el mejor :)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
3
En bash también puede usar $((0xff)), es decir, con prefijo hexadecimal tipo C en lugar de 16#, aunque N#es claramente más general.
Ruslan
3
El primer ejemplo de bash es susceptible al error de desbordamiento de enteros, por ejemplo, echo $((077E9F2DBF49D100001#FF))desborda el límite de enteros de 64 bits de 2 ^ 64. bcmaneja esto correctamente.
roblogic
39

Tratar con una versión incrustada muy ligera de busybox en Linux significa que muchos de los comandos tradicionales no están disponibles (bc, printf, dc, perl, python)

echo $((0x2f))
47

hexNum=2f
echo $((0x${hexNum}))
47

Gracias a Peter Leung por esta solución.

hinekyle
fuente
1
Está bien, pero tenga cuidado con el error de desbordamiento de enteros, por ejemplo, echo $((0x077E9F2DBF49D100001))desborda el límite de entero de 64 bits de 2 ^ 64. bcmaneja esto correctamente
roblogic
13

Una forma más de hacerlo usando el shell (bash o ksh, no funciona con el tablero):

echo $((16#FF))
255
Tomás Fox
fuente
¿Qué significa el #símbolo? ¿Hay alguna otra aplicación o documentación para leer más sobre su uso?
user1527227
1
Se menciona aquí: enlace . Al final de la sección 6.5 dice: "... los números toman la forma [base #] n, donde la base opcional es un número decimal entre 2 y 64 que representa la base aritmética, yn es un número en esa base. Si se omite base #, luego se utiliza base 10. Los dígitos mayores que 9 están representados por las letras minúsculas, las letras mayúsculas, '@' y '_', en ese orden. Si la base es menor o igual a 36, las letras minúsculas y mayúsculas se pueden usar indistintamente para representar números entre 10 y 35 ".
Tomás Fox
11

Hay varias herramientas disponibles desde dentro de un shell. Sputnick le ha dado una excelente visión general de sus opciones, en función de su pregunta inicial. Definitivamente merece votos por el tiempo que pasó dándole múltiples respuestas correctas.

Uno más que no está en su lista:

[ghoti@pc ~]$ dc -e '16i BFCA3000 p'
3217698816

Pero si todo lo que quiere hacer es restar, ¿por qué molestarse en cambiar la entrada a la base 10?

[ghoti@pc ~]$ dc -e '16i BFCA3000 17FF - p 10o p'
3217692673
BFCA1801
[ghoti@pc ~]$ 

El dccomando es "desk calc". También tomará información de stdin, como bc, pero en lugar de usar el "orden de operaciones", usa la notación de apilamiento ("polaco inverso"). Le das entradas que agrega a una pila, luego le das operadores que sacan elementos de la pila y retroceden en los resultados.

En los comandos anteriores tenemos lo siguiente:

  • 16i- le dice a dc que acepte la entrada en la base 16 (hexadecimal). No cambia la base de salida.
  • BFCA3000 - su número inicial
  • 17FF - un número hexadecimal aleatorio que elegí para restar de tu número inicial
  • - - tome los dos números que hemos empujado, reste el último del anterior, luego vuelva a colocar el resultado en la pila
  • p- Imprime el último elemento en la pila. Esto no cambia la pila, así que ...
  • 10o - le dice a dc que imprima su salida en la base "10", pero recuerde que nuestro esquema de numeración de entrada es actualmente hexadecimal, por lo que "10" significa "16".
  • p - imprime el último elemento en la pila de nuevo ... esta vez en hexadecimal.

Puedes construir soluciones matemáticas fabulosamente complejas con dc. Es bueno tener en su caja de herramientas para los scripts de shell.

ghoti
fuente
3

El error como se informa aparece cuando las variables son nulas (o vacías):

$ unset var3 var4; var5=$(($var4-$var3))
bash: -: syntax error: operand expected (error token is "-")

Eso podría suceder porque el valor dado a bc era incorrecto. Bien podría ser que bc necesita valores MAYÚSCULAS. Necesita BFCA3000, no bfca3000. Eso se arregla fácilmente en bash, solo usa la ^^expansión:

var3=bfca3000; var3=`echo "ibase=16; ${var1^^}" | bc`

Eso cambiará el guión a esto:

#!/bin/bash

var1="bfca3000"
var2="efca3250"

var3="$(echo "ibase=16; ${var1^^}" | bc)"
var4="$(echo "ibase=16; ${var2^^}" | bc)"

var5="$(($var4-$var3))"

echo "Diference $var5"

Pero no hay necesidad de usar bc [1], ya que bash podría realizar la traducción y sustracción directamente:

#!/bin/bash

var1="bfca3000"
var2="efca3250"

var5="$(( 16#$var2 - 16#$var1 ))"

echo "Diference $var5"

[1] Nota: Supongo que los valores podrían representarse en matemáticas de 64 bits, ya que la diferencia se calculó en bash en su script original. Bash está limitado a enteros menores que ((2 ** 63) -1) si se compila en 64 bits. Esa será la única diferencia con bc que no tiene ese límite.


fuente
3

En el tablero y otros proyectiles, puede usar

printf "%d\n" (your hexadecimal number)

para convertir un número hexadecimal a decimal. Esto no es bash, o ksh, específico.

principiante
fuente
1
por ejemploprintf "%d" 0xff
lashgar