Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 931
splinux Avatar asked Dec 02 '22 18:12

splinux


2 Answers

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
like image 159
dogbane Avatar answered Dec 19 '22 06:12

dogbane


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}'
like image 45
Gunstick Avatar answered Dec 19 '22 07:12

Gunstick