Hexadecimal To Decimal in Shell Script

BashShellHexDecimal

Bash Problem Overview


Can someone help me to convert a hexadecimal number to decimal number in a shell script?

E.g., I want to convert the hexadecimal number bfca3000 to decimal using a shell script. I basically want the difference of two hexadecimal numbers.

My code is:

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

When executing, I get this error:

Line 48: -: syntax error: operand expected (error token is "-")

Bash Solutions


Solution 1 - Bash

To convert from hex to decimal, there are many ways to do it in the shell or with an external program:

With [tag:bash]:

$ echo $((16#FF))
255

with [tag:bc]:

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

with [tag:perl]:

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

with [tag:printf] :

$ printf "%d\n" 0xFF
255

with [tag:python]:

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

with [tag:ruby]:

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

with [tag:node.js]:

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

with [tag:rhino]:

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

with [tag:groovy]:

$ groovy -e 'println Integer.parseInt("FF",16)'
255

Solution 2 - Bash

Dealing with a very lightweight embedded version of busybox on Linux means many of the traditional commands are not available (bc, printf, dc, perl, python)

echo $((0x2f))
47

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

Credit to Peter Leung for this solution.

Solution 3 - Bash

One more way to do it using the shell (bash or ksh, doesn't work with dash):

echo $((16#FF))
255

Solution 4 - Bash

Various tools are available to you from within a shell. Sputnick has given you an excellent overview of your options, based on your initial question. He definitely deserves votes for the time he spent giving you multiple correct answers.

One more that's not on his list:

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

But if all you want to do is subtract, why bother changing the input to base 10?

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

The dc command is "desk calc". It will also take input from stdin, like bc, but instead of using "order of operations", it uses stacking ("reverse Polish") notation. You give it inputs which it adds to a stack, then give it operators that pop items off the stack, and push back on the results.

In the commands above we've got the following:

  • 16i -- tells dc to accept input in base 16 (hexadecimal). Doesn't change output base.
  • BFCA3000 -- your initial number
  • 17FF -- a random hex number I picked to subtract from your initial number
  • - -- take the two numbers we've pushed, and subtract the later one from the earlier one, then push the result back onto the stack
  • p -- print the last item on the stack. This doesn't change the stack, so...
  • 10o -- tells dc to print its output in base "10", but remember that our input numbering scheme is currently hexadecimal, so "10" means "16".
  • p -- print the last item on the stack again ... this time in hex.

You can construct fabulously complex math solutions with dc. It's a good thing to have in your toolbox for shell scripts.

Solution 5 - Bash

In dash and other shells, you can use

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

to convert a hexadecimal number to decimal. This is not specific to bash or ksh.

Solution 6 - Bash

The error as reported appears when the variables are null (or empty):

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

That could happen because the value given to bc was incorrect. That might well be that bc needs UPPERcase values. It needs BFCA3000, not bfca3000. That is easily fixed in bash, just use the ^^ expansion:

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

That will change the script to this:

#!/bin/bash

var1="bfca3000"
var2="efca3250"

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

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

echo "Diference $var5"

But there is no need to use bc [1], as bash could perform the translation and substraction directly:

#!/bin/bash

var1="bfca3000"
var2="efca3250"

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

echo "Diference $var5"

[1]Note: I am assuming the values could be represented in 64 bit math, as the difference was calculated in bash in your original script. Bash is limited to integers less than ((2**63)-1) if compiled in 64 bits. That will be the only difference with bc which does not have such limit.

Solution 7 - Bash

Shortest way yet:

$ echo $[0x3F]
63

Solution 8 - Bash

I have this handy script on my $PATH to filter 0x1337-like; 1337; or "0x1337" lines of input into decimal strings (expanded for clarity):

#!/usr/bin/env bash

while read data; do
  withoutQuotes=`echo ${data} | sed s/\"//g`
  without0x=`echo ${withoutQuotes} | sed s/0x//g`
  clean=${without0x}
  echo $((16#${clean}))
done

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVenkateshJNView Question on Stackoverflow
Solution 1 - BashGilles QuenotView Answer on Stackoverflow
Solution 2 - BashhinekyleView Answer on Stackoverflow
Solution 3 - BashTomás FoxView Answer on Stackoverflow
Solution 4 - BashghotiView Answer on Stackoverflow
Solution 5 - BashnoviceView Answer on Stackoverflow
Solution 6 - Bashuser2350426View Answer on Stackoverflow
Solution 7 - BashKostasView Answer on Stackoverflow
Solution 8 - BasheordanoView Answer on Stackoverflow