Hexadecimal conversion in bash/awk

Let’s suppose we have a number expressed in given base (i.e. “E0″ in hexadecimal). How can we convert it to decimal using bash or other common Unix tools? And what if we need to perform an any-to-any base conversion?

First way: printf + hexdump

We can tell bash that a given string is just a disguised hexadecimal number by adding “\x” at the top of it and then using the built-in printf function to recover the number:

$ foo="6F"
$foo2="\x"$foo
$ printf "%b" $foo2 | hexdump -e '1/1 "%d" "\n"'
111
$ printf "%b" $foo2 | hexdump -e '1/1 "%o" "\n"'
157

Please notice that %d makes hexdumo to return a signed integer; if you need an unsigned integer just replace it with %u:

$ printf "%b" "\x8F" | hexdump -e '1/1 "%d" "\n"'
-113
$ printf "%b" "\x8F" | hexdump -e '1/1 "%u" "\n"'
143

Second way: bc

bc allows you to set the base of the input numbers and the one for the output (default is decimal) by using respectively ibase and obase variables. So we just need to type:

$ foo="6F"
$ echo "ibase=16; $foo" | bc
111
$ echo "ibase=16; obase=8; $foo" | bc
157

Third way: dc

dc is a little tricky and confusing at the beginning only because it uses RPN (reverse polish notation). That means that if we want to calculate 1+2, we have to type the addends first and then the plus sign:

$ echo "1 2 + p" | dc
3

Nonetheless, dc is another powerful unix tool which can make you solve math or pseudo-math problems without leaving your console.
Just as in our case:

$ foo=6F
$ echo "16 i $foo p" | dc
111
$ echo "16 i 8 o $foo p" | dc
157

First line just sets the input base to hexadecimal (16 i), then pushes 6F into the stack’s head and then prints it. The second in addition to it, sets the output base to the octal one, so that 6F is printed in octal notation.

Fourth way: awk general base converter script

Here is a non-optimised not-much-tested awk script that will convert a number in a given base to any other given base. It should work from base 2 to base 36 (do they really exist?).

#!/usr/bin/awk -f

{
    #our general alphabet
    alphabet="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    # input base
    ibase=$1;

    # output base
    obase=$2;

    #convert third parameter to decimal base
    for (i=1;i<=length($3);i++) {
        number += substr($3,i,1)*(ibase^(length($3)-i));

    }
    tmp=number;

    #convert "number" to the output base
    while (tmp>=obase) {
        nut=substr(alphabet,tmp%obase+1,1);
        final = nut final;
        tmp=int(tmp/obase);
    }
    final = substr(alphabet,tmp%obase+1,1) final;

    printf("%s (b %s) -> %s (b 10) -> %s (b %s)\n",$3,ibase,number,final,obase);
}
Special case: number to char and viceversa

In many low-level languages like C a char is just a byte so you normally think of it just a normal number. On the other hand, bash scripting language a string is generally not a number. However, we can force bash to convert a char to a number and viceversa by using printf:

$ foo=x
echo -n $foo | xxd -c 1 -p
77
printf "%b\n" "\x77"
x

None
A comma-separated list of terms describing this content. Example: funny, bungee jumping, "Company, Inc.".