Convert a decimal number to hexadecimal and binary in a shell script

17,081

Solution 1

The following one-liner should work:

printf "%s %08d 0x%02x\n" "$1" $(bc <<< "ibase=10;obase=2;$1") "$1"

Example output:

$ for i in {1..10}; do printf "%s %08d 0x%02x\n" "$i" $(bc <<< "ibase=10;obase=2;$i") "$i"; done
1 00000001 0x01
2 00000010 0x02
3 00000011 0x03
4 00000100 0x04
5 00000101 0x05
6 00000110 0x06
7 00000111 0x07
8 00001000 0x08
9 00001001 0x09
10 00001010 0x0a

Solution 2

So I searched for a short and elegant awk binary converter. Not satisfied considered this as a challenge, so here you are. A little bit optimzed for size, so I put a readable version below.

The printf at the end specifies how large the numbers should be. In this case 8 bits.

Is this bad code? Hmm, yeah... it's awk :-) Does of course not work with very huge numbers.

67 characters long awk code:

awk '{r="";a=$1;while(a){r=((a%2)?"1":"0")r;a=int(a/2)}printf"%08d\n",r}'

Edit: 55 characters awk code

awk '{r="";a=$1;while(a){r=a%2r;a=int(a/2)}printf"%08d\n",r}'

Readable version:

awk '{r=""                    # initialize result to empty (not 0)
      a=$1                    # get the number
      while(a!=0){            # as long as number still has a value
        r=((a%2)?"1":"0") r   # prepend the modulos2 to the result
        a=int(a/2)            # shift right (integer division by 2)
      }
      printf "%08d\n",r       # print result with fixed width
     }'

And the asked one liner with bin and hex

awk '{r="";a=$1;while(a){r=a%2r;a=int(a/2)}printf"%08d 0x%02x\n",r,$1}'

Solution 3

You don't need bc. Here's a solution using only awk:

  • Fetch the bits2str function available in the manual
  • Add this minimal script:

    {
        printf("%s %s %x\n", $1, bits2str($1), $1)
    }
    

This produces:

$ awk -f awkscr.awk nums 
1 00000001 1
2 00000010 2
3 00000011 3
Share:
17,081
splinux
Author by

splinux

C/C++ and Java developer

Updated on June 08, 2022

Comments

  • splinux
    splinux almost 2 years

    I have a decimal number in each line of a file.txt:

        1
        2
        3
    

    I am trying (for too long now) to write a one-liner script to have an output where each row has a column with the decimal, hexadecimal and the binary. To ease the task we can say that the original number is expressed in a byte. So the maximum value is 255.

    1. I first try to decode each number as a bynary with prepended 0 so to have an 8 bits pattern:

      awk '{print "ibase=10;obase=2;" $1}' $1 | bc | xargs printf "%08d\n"

      where the outer $1 in the awk statement is file.txt. The output is :

      00000001
      00000010
      00000011
      
    2. Same for hex with one prepended 0

      awk '{printf("0x%02x\n", $1)}' $1

      Same as before. The Output is :

      0x01
      0x02
      0x03
      
    3. Well, the decimal should be just a print:

      1
      2
      3
      

    What I'd like to have is one liner where I have:

        1 00000001 0x01
        2 00000001 0x02
    

    so basically to put 1. 2. and 3. in each line of the output.

    I tried to execute bc (and other command) within awk using system() without success. And a zillion other ways. What is the way you would do it?