26

In Bash, how does one do base conversion from decimal to another base, especially hex. It seems easy to go the other way:

$ echo $((16#55))
85

With a web-search, I found a script that does the maths and character manipulation to do the conversion, and I could use that as a function, but I'd have thought that bash would already have a built-in base conversion -- does it?

35

With bash (or any shell, provided the printf command is available (a standard POSIX command often built in the shells)):

printf '%x\n' 85

​​​​​​​​​​​​​​​​​ With zsh, you can also do:

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

That works for bases from 2 to 36 (with 0-9a-z case insensitive as the digits).

With ksh93, you can use:

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

Which works for bases from 2 to 64 (with 0-9a-zA-Z@_ as the digits).

With ksh and zsh, there's also:

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

Though that's limited to bases up to 36 in ksh88, zsh and pdksh and 64 in ksh93.

Note that all those are limited to the size of the long integers on your system (int's with some shells). For anything bigger, you can use bc or dc.

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

With supported bases ranging from 2 to some number required by POSIX to be at least as high as 99. For bases greater than 16, digits greater than 9 are represented as space-separated 0-padded decimal numbers.

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

Or same with dc (bc used to be (and still is on some systems) a wrapper around dc):

$ echo 30o123456p | dc
 04 17 05 06
  • Thanks. Exactly what I was looking for. (And embarrassingly simple.) – Dave Rove Mar 19 '15 at 13:32
  • What if you want to do an arbitrary base like you can specify with #? – flarn2006 Sep 27 '16 at 18:29
  • @flarn2006. With bash builtins, you can input numbers in any base, but not output in any base other than 8, 10 and 16. For other bases, you'd need another shell like zsh or ksh or use bc/dc. – Stéphane Chazelas Sep 27 '16 at 20:27
  • 1
    @StéphaneChazelas Really? That's kind of weird. It almost seems like they were too lazy to program in a syntax for it or something; there's no way the idea of outputting in any base didn't cross their minds if they implemented inputting. – flarn2006 Sep 28 '16 at 1:11
  • alias hex="printf '%x\n'" – mwfearnley yesterday
5

Use printf:

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

To assign the value to a variable use command substitution:

$ x=$( printf "%x" 85 ) ; echo $x
55
  • 4
    Or, use the -v option for the builtin printf: printf -v foo "%d" $((16#BEEF)); echo $foo – glenn jackman Mar 19 '15 at 13:37
  • @Glenn Using non-standard options (like -v) is unnecessary here; I'd avoid it. – Janis Mar 19 '15 at 13:40
  • 3
    -v would avoid the fork and pipe (in bash, not ksh93 which wouldn't fork here as printf is builtin). Note that $((16#55)) is not standard either. – Stéphane Chazelas Mar 19 '15 at 13:42
  • @StéphaneChazelas, wait a minute. Are you saying that ksh93 does not fork for x=$(some_builtin) ? – glenn jackman Mar 19 '15 at 13:44
  • 1
    @glennjackman, yes, it only forks for executing external commands. – Stéphane Chazelas Mar 19 '15 at 13:45
1

Use the built-in Arithmetic Expansion substitution present in all POSIX compliant shells - which is pretty much universal these days.

$ echo $((0xbc))
188

and

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

CAUTION: Particularly in the last example the expansion could cause unexpected results - the hex digits in the variable 'hex' have to form a legal hex constant, otherwise potentially obscure error messages happen. e.g. if 'hex' were '0xdead', the arithmetic expansion would become 0x0xdead, which is not interpretable as a constant. Of course, in that case the arithmetic expansion $(($hex)) would do the trick. It is left as an exercise for the reader to create the simple substring processing pattern matching that would remove an optional '0x' prefix.

  • 4
    You're doing the exact same thing the OP did in his example; he's looking for the reverse operation. – Thomas Guyot-Sionnest Feb 9 '16 at 6:48
0

You can use the awk Velour library:

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

Or:

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.