127

In a UNIX shell script, what can I use to convert decimal numbers into hexadecimal? I thought od would do the trick, but it's not realizing I'm feeding it ASCII representations of numbers.

printf? Gross! Using it for now, but what else is available?

Zombo
  • 1
  • 62
  • 391
  • 407
skiphoppy
  • 97,646
  • 72
  • 174
  • 218
  • 10
    I have to ask, what's gross about printf? Many common programming languages support printf-like formatting, so the printf solutions below would surely be the easiest for developers to understand. – Michael Scheper Nov 29 '13 at 00:30
  • 5
    Boy, I don't know - that was five years ago! I think maybe I thought it wasn't true shell or something. – skiphoppy Dec 06 '13 at 03:36

13 Answers13

215

Tried printf(1)?

printf "%x\n" 34
22

There are probably ways of doing that with builtin functions in all shells but it would be less portable. I've not checked the POSIX sh specs to see whether it has such capabilities.

Keltia
  • 14,535
  • 3
  • 29
  • 30
121
echo "obase=16; 34" | bc

If you want to filter a whole file of integers, one per line:

( echo "obase=16" ; cat file_of_integers ) | bc
Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • 1
    I looked at both bc(1) and dc(1) and missed that one. – Keltia Dec 18 '08 at 21:58
  • Any way to turn it into a filter that'll take an arbitrary number of integers, all on one line? – skiphoppy Dec 19 '08 at 02:00
  • 3
    @skiphoppy: If you write: echo "obase=16; 12 34 56" | bc you get 1E240, just the same as if you wrote: echo "obase=16; 123456" | bc. So the way to deal with arbitrary numbers of integers all on one line is to put each number on its own line: tr ' ' '\015' – Jonathan Leffler Dec 25 '08 at 20:40
  • 2
    This is great if you happen to have 'bc', but 'printf' is part of bash itself – fuzzyTew Jul 12 '13 at 10:29
  • 1
    @fuzzyTew, sure, that's true. But only if you have bash. :-) – Bill Karwin Jul 12 '13 at 17:06
  • 2
    @Bill Karwin, or zsh, or busybox, but maybe not some shell I haven't tried? I don't keep plain sh installed anymore but clearly skiphoppy is looking for what other options there are – fuzzyTew Jul 13 '13 at 21:48
  • I like the piping aspect of this, but how do you do the reverse? From decimal to hexadecimal? – Sridhar Sarnobat May 27 '15 at 20:35
  • 2
    @Sridhar-Sarnobat, this *is* decimal to hexadecimal. I assume you mean convert hex to dec. To do that, set `ibase=16`. You might like to read the [manual on bc](http://www.gnu.org/software/bc/manual/html_mono/bc.html) for more details. – Bill Karwin May 28 '15 at 01:58
  • 2
    you would like to add that bc is case sensitive. meaning `echo "ibase=16; dead" | bc` will not work, you need to do `echo "ibase=16; DEAD" | bc`, I was bit surprised by this – graywolf Aug 18 '16 at 11:18
79

Hexidecimal to decimal:

$ echo $((0xfee10000))
4276158464

Decimal to hexadecimal:

$ printf '%x\n' 26
1a
Matthieu
  • 2,736
  • 4
  • 57
  • 87
pjhobbs
  • 913
  • 7
  • 2
18
bash-4.2$ printf '%x\n' 4294967295
ffffffff

bash-4.2$ printf -v hex '%x' 4294967295
bash-4.2$ echo $hex
ffffffff
Orwellophile
  • 13,235
  • 3
  • 69
  • 45
  • 2
    `-v VAR` is a bash extension. Not mentioned in the [man page](https://linux.die.net/man/1/printf), revealed only if one calls `printf` without arguments – Adrian W Oct 24 '18 at 10:19
  • 3
    @AdrianW it's in the manual: https://www.gnu.org/software/bash/manual/bash.html#Bash-Builtins – Roland Jul 20 '21 at 12:34
  • @AdrianW There's no dedicated man page for it because it's a bash builtin. Those are documented in `man bash`. Or, as with any builtin, you can do `help printf`. (`man printf` shows documentation for the separate, standalone program `printf`.) – B Layer Aug 25 '23 at 00:09
7

Sorry my fault, try this...

#!/bin/bash
:

declare -r HEX_DIGITS="0123456789ABCDEF"

dec_value=$1
hex_value=""

until [ $dec_value == 0 ]; do

    rem_value=$((dec_value % 16))
    dec_value=$((dec_value / 16))

    hex_digit=${HEX_DIGITS:$rem_value:1}

    hex_value="${hex_digit}${hex_value}"

done

echo -e "${hex_value}"

Example:

$ ./dtoh 1024
400
kenorb
  • 155,785
  • 88
  • 678
  • 743
pjhobbs
  • 913
  • 7
  • 2
5

Try:

printf "%X\n" ${MY_NUMBER}
Rob Wells
  • 36,220
  • 13
  • 81
  • 146
  • 1
    What is the difference between `$MY_NUMBER` and `${MY_NUMBER}` ? – SasQ Sep 05 '20 at 04:43
  • 1
    @SasQ using brackets forces interpretation of the symbol that you intended to be used, i.e. just MY_NUMBER. Using brackets allows you to do things like ${MY_TEXT_FRAG_${MY_NUMBER}} to concatenate variable names. – Rob Wells Sep 07 '20 at 16:08
3

In my case, I stumbled upon one issue with using printf solution:

$ printf "%x" 008 bash: printf: 008: invalid octal number

The easiest way was to use solution with bc, suggested in post higher:

$ bc <<< "obase=16; 008" 8

DJ83
  • 67
  • 3
  • What does your solution add to the ones written years before? – Matthieu Aug 17 '18 at 16:53
  • 1
    @Matthieu It mentions the issue of numbers with leading zeros, which Bash printf unhelpfully interprets as octal, and demonstrates a solution that avoids the problem. – mwfearnley Oct 21 '19 at 14:56
3

In zsh you can do this sort of thing:

% typeset -i 16 y
% print $(( [#8] x = 32, y = 32 ))
8#40
% print $x $y
8#40 16#20
% setopt c_bases
% print $y
0x20

Example taken from zsh docs page about Arithmetic Evaluation.

I believe Bash has similar capabilities.

kenorb
  • 155,785
  • 88
  • 678
  • 743
Alastair
  • 4,475
  • 1
  • 26
  • 23
2
xd() {
    printf "hex> "
    while read i
    do
        printf "dec  $(( 0x${i} ))\n\nhex> "
    done
}
dx() {
    printf "dec> "
    while read i
    do
        printf 'hex  %x\n\ndec> ' $i
    done
}
sjas
  • 18,644
  • 14
  • 87
  • 92
1
# number conversion.

while `test $ans='y'`
do
    echo "Menu"
    echo "1.Decimal to Hexadecimal"
    echo "2.Decimal to Octal"
    echo "3.Hexadecimal to Binary"
    echo "4.Octal to Binary"
    echo "5.Hexadecimal to  Octal"
    echo "6.Octal to Hexadecimal"
    echo "7.Exit"

    read choice
    case $choice in

        1) echo "Enter the decimal no."
           read n
           hex=`echo "ibase=10;obase=16;$n"|bc`
           echo "The hexadecimal no. is $hex"
           ;;

        2) echo "Enter the decimal no."
           read n
           oct=`echo "ibase=10;obase=8;$n"|bc`
           echo "The octal no. is $oct"
           ;;

        3) echo "Enter the hexadecimal no."
           read n
           binary=`echo "ibase=16;obase=2;$n"|bc`
           echo "The binary no. is $binary"
           ;;

        4) echo "Enter the octal no."
           read n
           binary=`echo "ibase=8;obase=2;$n"|bc`
           echo "The binary no. is $binary"
           ;;

        5) echo "Enter the hexadecimal no."
           read n
           oct=`echo "ibase=16;obase=8;$n"|bc`
           echo "The octal no. is $oct"
           ;;

        6) echo "Enter the octal no."
           read n
           hex=`echo "ibase=8;obase=16;$n"|bc`
           echo "The hexadecimal no. is $hex"
           ;;

        7) exit 
        ;;
        *) echo "invalid no." 
        ;;

    esac
done
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
1

This is not a shell script, but it is the cli tool I'm using to convert numbers among bin/oct/dec/hex:

    #!/usr/bin/perl

    if (@ARGV < 2) {
      printf("Convert numbers among bin/oct/dec/hex\n");
      printf("\nUsage: base b/o/d/x num num2 ... \n");
      exit;
    }

    for ($i=1; $i<@ARGV; $i++) {
      if ($ARGV[0] eq "b") {
                    $num = oct("0b$ARGV[$i]");
      } elsif ($ARGV[0] eq "o") {
                    $num = oct($ARGV[$i]);
      } elsif ($ARGV[0] eq "d") {
                    $num = $ARGV[$i];
      } elsif ($ARGV[0] eq "h") {
                    $num = hex($ARGV[$i]);
      } else {
                    printf("Usage: base b/o/d/x num num2 ... \n");
                    exit;
      }
      printf("0x%x = 0d%d = 0%o = 0b%b\n", $num, $num, $num, $num);
    }
CodyChan
  • 1,776
  • 22
  • 35
0

For those who would like to use variables, first export it by running:

export NUM=100

Then run:

printf "%x\n" $NUM

Else, you can you can ignore the use case of the variables and run it directly as shown below:

printf "%x\n" 100

NB:Substitute NUM with the variable name of your choice.

Exporting makes it an environmental variable(global).

-2

Wow, I didn't realize that printf was available at the shell!

With that said, I'm surprised no-one commented about putting the printf into a shell script (which then you could put in your personal bin directory if you wanted).

echo "printf "0x%x\n" $1" > hex chmod +x hex

Now just run: ./hex 123

It returns: 0x7b