Conversão base BASH de decimal para hex

29

No Bash, como se faz a conversão de base de decimal para outra base, especialmente hexadecimal. Parece fácil seguir o outro caminho:

$ echo $((16#55))
85

Com uma pesquisa na web, encontrei um script que manipula matemática e caracteres para fazer a conversão, e eu poderia usá-lo como uma função, mas pensei que o bash já teria uma conversão básica embutida - faz isso?

Dave Rove
fonte
stackoverflow.com/questions/378829/…
Ciro Santilli escreveu:

Respostas:

35

Com bash(ou qualquer shell, desde que o printfcomando esteja disponível (um comando POSIX padrão, geralmente construído nos shells)):

printf '%x\n' 85

Com zsh, você também pode fazer:

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

Isso funciona para bases de 2 a 36 (com 0-9a-zdistinção entre maiúsculas e minúsculas como os dígitos).

Com ksh93, você pode usar:

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

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

Com kshe zsh, há também:

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

Embora isso seja limitado a bases de até 36 em ksh88, zsh e pdksh e 64 em ksh93.

Observe que todos esses são limitados ao tamanho dos longnúmeros inteiros no seu sistema ( intcom alguns shells). Para qualquer coisa maior, você pode usar bcou dc.

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

Com bases suportadas que variam de 2 a algum número exigido pelo POSIX, pelo menos, até 99. Para bases maiores que 16, dígitos maiores que 9 são representados como números decimais preenchidos com 0 e separados por espaço.

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

Ou o mesmo com dc( bccostumava ser (e ainda está em alguns sistemas) um invólucro dc):

$ echo 30o123456p | dc
 04 17 05 06
Stéphane Chazelas
fonte
Obrigado. Exatamente o que eu estava procurando. (E constrangedoramente simples.)
Dave Rove
E se você quiser fazer uma base arbitrária como pode especificar #?
precisa saber é o seguinte
@ flarn2006. Com bashbuiltins, você pode entrada números em qualquer base, mas não de saída em qualquer base diferente de 8, 10 e 16. Para outras bases, você precisa de outro shell como zshou kshou utilização bc/dc.
Stéphane Chazelas
11
@ StéphaneChazelas Realmente? Isso é meio estranho. Parece quase que eles estavam com preguiça de programar em uma sintaxe para isso ou algo assim; não há como a idéia de produzir em qualquer base não passar pela cabeça deles se eles implementarem a inserção.
precisa saber é o seguinte
alias hex="printf '%x\n'"
mwfearnley 21/10
5

Use printf:

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

Para atribuir o valor a uma variável, use a substituição de comando:

$ x=$( printf "%x" 85 ) ; echo $x
55
Janis
fonte
4
Ou use a -vopção para o printf interno:printf -v foo "%d" $((16#BEEF)); echo $foo
glenn jackman
@ Glenn Usar opções não padrão (como -v) é desnecessário aqui; Eu evitaria isso.
Janis
3
-vevitaria o garfo e o tubo (no bash, não o ksh93, que não se bifurca aqui como printfestá embutido). Observe que $((16#55))também não é padrão.
Stéphane Chazelas 19/03/2015
@ StéphaneChazelas, espere um minuto. Você está dizendo que o ksh93 não bifurca x=$(some_builtin)?
Glenn Jackman
11
@glennjackman, sim, apenas bifurca-se para executar comandos externos.
Stéphane Chazelas 19/03/2015
2

Use a substituição de expansão aritmética integrada presente em todos os shells compatíveis com POSIX - que é praticamente universal nos dias de hoje.

$ echo $((0xbc))
188

e

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

CUIDADO: Particularmente no último exemplo, a expansão pode causar resultados inesperados - os dígitos hexadecimais na variável 'hex' precisam formar uma constante hexadecimal legal, caso contrário, mensagens de erro potencialmente obscuras ocorrem. por exemplo, se 'hex' fosse '0xdead', a expansão aritmética se tornaria 0x0xdead, o que não é interpretável como uma constante. Obviamente, nesse caso, a expansão aritmética $ (($ hex)) faria o truque. É deixado como um exercício para o leitor criar a correspondência simples de padrão de processamento de substring que removeria um prefixo '0x' opcional.

Mark van der Pol
fonte
4
Você está fazendo exatamente a mesma coisa que o OP fez no exemplo dele; ele está procurando a operação reversa .
Thomas Guyot-Sionnest
0

Você pode usar a biblioteca 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
fonte