BASH conversión de base de decimal a hexadecimal

29

En Bash, ¿cómo se hace una conversión de base de decimal a otra base, especialmente hexadecimal? Parece fácil ir a la inversa:

$ echo $((16#55))
85

Con una búsqueda en la web, encontré un script que hace las matemáticas y la manipulación de caracteres para hacer la conversión, y podría usar eso como una función, pero hubiera pensado que bash ya tendría una conversión de base incorporada: ¿lo hace?

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

Respuestas:

35

Con bash(o cualquier shell, siempre que el printfcomando esté disponible (un comando POSIX estándar a menudo integrado en los shells)):

printf '%x\n' 85

Con zsh, también puedes hacer:

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

Eso funciona para bases del 2 al 36 (con 0-9a-zmayúsculas y minúsculas como dígitos).

Con ksh93, puedes usar:

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

Que funciona para bases de 2 a 64 (con 0-9a-zA-Z@_los dígitos).

Con kshy zsh, también hay:

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

Aunque eso se limita a bases de hasta 36 en ksh88, zsh y pdksh y 64 en ksh93.

Tenga en cuenta que todos estos están limitados al tamaño de los longenteros en su sistema ( intcon algunos shells). Para cualquier cosa más grande, puedes usar bco dc.

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

Con bases admitidas que van desde 2 hasta algún número, POSIX requiere que sea al menos tan alto como 99. Para bases mayores que 16, los dígitos mayores que 9 se representan como números decimales con relleno de 0 separados por espacios.

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

O lo mismo con dc( bcsolía ser (y todavía está en algunos sistemas) una envoltura dc):

$ echo 30o123456p | dc
 04 17 05 06
Stéphane Chazelas
fuente
Gracias. Exactamente lo que estaba buscando. (Y vergonzosamente simple.)
Dave Rove
¿Qué sucede si desea hacer una base arbitraria como puede especificar #?
flarn2006
@ flarn2006. Con las bashfunciones integradas, puede ingresar números en cualquier base, pero no generar en ninguna base que no sea 8, 10 y 16. Para otras bases, necesitaría otro shell como zsho ksho uso bc/dc.
Stéphane Chazelas
1
@ StéphaneChazelas ¿En serio? Eso es un poco raro. Casi parece que fueron demasiado flojos para programar en una sintaxis para eso o algo así; no hay forma de que la idea de producir en cualquier base no se les pase por la cabeza si implementan la entrada.
flarn2006
alias hex="printf '%x\n'"
mwfearnley
5

Use printf:

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

Para asignar el valor a una variable, utilice la sustitución de comandos:

$ x=$( printf "%x" 85 ) ; echo $x
55
Janis
fuente
44
O utilice la -vopción para la impresión integrada:printf -v foo "%d" $((16#BEEF)); echo $foo
Glenn Jackman
@Glenn Usar opciones no estándar (como -v) es innecesario aquí; Lo evitaría
Janis
3
-vevitaría la bifurcación y la tubería (en bash, no ksh93 que no se bifurcaría aquí como printfestá incorporado). Tenga en cuenta que $((16#55))tampoco es estándar.
Stéphane Chazelas
@ StéphaneChazelas, espera un minuto. ¿Estás diciendo que ksh93 no se bifurca x=$(some_builtin)?
Glenn Jackman
1
@glennjackman, sí, solo se bifurca para ejecutar comandos externos.
Stéphane Chazelas
2

Utilice la sustitución de expansión aritmética incorporada presente en todos los shells compatibles con POSIX, que es bastante universal en estos días.

$ echo $((0xbc))
188

y

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

PRECAUCIÓN: Particularmente en el último ejemplo, la expansión podría causar resultados inesperados: los dígitos hexadecimales en la variable 'hexadecimal' deben formar una constante hexadecimal legal; de lo contrario, pueden aparecer mensajes de error potencialmente oscuros. por ejemplo, si 'hex' fuera '0xdead', la expansión aritmética se convertiría en 0x0xdead, lo que no se puede interpretar como una constante. Por supuesto, en ese caso la expansión aritmética $ (($ hex)) haría el truco. Se deja como ejercicio para que el lector cree la coincidencia de patrón de procesamiento de subcadena simple que eliminaría un prefijo opcional '0x'.

Mark van der Pol
fuente
44
Estás haciendo exactamente lo mismo que hizo el OP en su ejemplo; Está buscando la operación inversa .
Thomas Guyot-Sionnest
0

Puede usar la biblioteca awk Velour :

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

O:

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