Hexadecimal para decimal em shell script

126

Alguém pode me ajudar a converter um número hexadecimal em número decimal em um script de shell?

Por exemplo, eu quero converter o número hexadecimal bfca3000em decimal usando um script de shell. Eu basicamente quero a diferença de dois números hexadecimais.

Meu código é:

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

Ao executar, recebo este erro:

Line 48: -: syntax error: operand expected (error token is "-")
VenkateshJN
fonte
O contrário: stackoverflow.com/questions/378829/… . Essencialmente as mesmas ferramentas. E possível duplicação de site cruzado de: superuser.com/questions/226163/…
Ciro Santilli, em

Respostas:

314

Para converter de hex para decimal, há muitas maneiras de fazer isso no shell ou com um programa externo:

Com :

$ echo $((16#FF))
255

com :

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

com :

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

com :

$ printf "%d\n" 0xFF
255

com :

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

com :

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

com :

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

com :

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

com :

$ groovy -e 'println Integer.parseInt("FF",16)'
255
Gilles Quenot
fonte
1
O que ? bc é uma linguagem arbitrária da calculadora de precisão : um comando externo.
Gilles Quenot
10
E entao ? esse é exatamente o objetivo dos meus 4 comandos antes de modificar o sentido da sua pergunta.
Gilles Quenot
2
A printfsolução é POSIX? Se sim, é o melhor :)
Ciro Santilli郝海东冠状病六四事件法轮功
3
No bash, você também pode usar $((0xff)), ou seja, com prefixo hexadecimal do tipo C em vez de 16#, embora N#seja claramente mais geral.
Ruslan #
3
O primeiro exemplo do bash é suscetível a erro de excesso de número inteiro, por exemplo, echo $((077E9F2DBF49D100001#FF))excede o limite inteiro de 64 bits de 2 ^ 64. bclida com isso corretamente.
roblogic
39

Lidar com uma versão incorporada muito leve do busybox no Linux significa que muitos dos comandos tradicionais não estão disponíveis (bc, printf, dc, perl, python)

echo $((0x2f))
47

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

Agradecemos a Peter Leung por esta solução.

hinekyle
fonte
1
OK, mas cuidado com o erro de número inteiro excedido, por exemplo, echo $((0x077E9F2DBF49D100001))excede o limite inteiro de 64 biit de 2 ^ 64. bclida com isso corretamente
roblogic
13

Mais uma maneira de fazer isso usando o shell (bash ou ksh, não funciona com o dash):

echo $((16#FF))
255
Tomás Fox
fonte
O que significa o #símbolo? Existem outros aplicativos ou documentação para ler mais sobre seu uso?
User1527227
1
É mencionado aqui: link . No final da seção 6.5, diz: "... os números assumem a forma [base #] n, onde a base opcional é um número decimal entre 2 e 64 representando a base aritmética, e n é um número nessa base. Se omissão da base # é omitida, a base 10. é usada. Os dígitos maiores que 9 são representados pelas letras minúsculas, maiúsculas '@' e '_', nessa ordem. Se a base for menor ou igual a 36, letras minúsculas e maiúsculas podem ser usadas de forma intercambiável para representar números entre 10 e 35. "
Tomás Fox
11

Várias ferramentas estão disponíveis para você a partir de um shell. Sputnick lhe deu uma excelente visão geral de suas opções, com base em sua pergunta inicial. Ele definitivamente merece votos pelo tempo que passou dando a você várias respostas corretas.

Mais um que não está na lista dele:

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

Mas se tudo o que você quer fazer é subtrair, por que se preocupar em mudar a entrada para a base 10?

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

O dccomando é "desk calc". Ele também recebe a entrada do stdin, como bc, mas em vez de usar a "ordem das operações", ele usa a notação de empilhamento ("polonês reverso"). Você fornece as entradas que adiciona a uma pilha, depois os operadores que retiram itens da pilha e pressionam os resultados.

Nos comandos acima, temos o seguinte:

  • 16i- diz ao dc para aceitar a entrada na base 16 (hexadecimal). Não altera a base de saída.
  • BFCA3000 - seu número inicial
  • 17FF - um número hexadecimal aleatório que escolhi para subtrair do seu número inicial
  • - - pegue os dois números que pressionamos e subtraia o último do anterior, depois empurre o resultado de volta para a pilha
  • p- imprima o último item na pilha. Isso não muda a pilha, então ...
  • 10o - diz ao dc para imprimir sua saída na base "10", mas lembre-se de que nosso esquema de numeração de entrada é atualmente hexadecimal, portanto "10" significa "16".
  • p - imprima o último item na pilha novamente ... desta vez em hexadecimal.

Você pode construir soluções matemáticas fabulosamente complexas com dc. É bom ter em sua caixa de ferramentas para scripts de shell.

ghoti
fonte
3

O erro conforme relatado aparece quando as variáveis ​​são nulas (ou vazias):

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

Isso poderia acontecer porque o valor dado a bc estava incorreto. Pode ser que o bc precise de valores UPPERcase. Precisa BFCA3000, não bfca3000. Isso é facilmente corrigido no bash, basta usar a ^^expansão:

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

Isso mudará o script para isso:

#!/bin/bash

var1="bfca3000"
var2="efca3250"

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

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

echo "Diference $var5"

Mas não há necessidade de usar bc [1], pois o bash poderia executar a tradução e a subação diretamente:

#!/bin/bash

var1="bfca3000"
var2="efca3250"

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

echo "Diference $var5"

[1] Nota: Estou assumindo que os valores possam ser representados na matemática de 64 bits, pois a diferença foi calculada no bash no seu script original. Bash é limitado a números inteiros menores que ((2 ** 63) -1) se compilados em 64 bits. Essa será a única diferença com bc que não possui esse limite.


fonte
3

No traço e outras conchas, você pode usar

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

para converter um número hexadecimal em decimal. Isso não é específico do bash ou do ksh.

novato
fonte
1
por exemploprintf "%d" 0xff
lashgar