Conversion from Hexadecimal to binary

How can I convert hexadecimal values to Binary from the second field to the end

Input:

WS-2 23 345 235
DT-3 45 4A3 000
pp-2 76 300 E4

Output:

WS-2 100011 1101000101 1000110101
DT-3 1000101 10010100011 000
pp-2 1110110 1100000000 11100100

Check "More UNIX and Linux Forum Topics You Might Find Helpful" suggested at the bottom of this thread

1 Like

I have gone through but could not get help

This works in the bash shell. It is a one-off hack, IMO. perl or some other interpreted language would be more efficient.

#!/bin/bash
#obase.shl - convert to binary from hex
while read rec
do
a=( $rec)
 (echo ${a[0]}
  echo "ibase=16; obase=2; ${a[1]}"  | bc -l
  echo "ibase=16; obase=2; ${a[2]}"  | bc -l) | tr -s  '\n' ' '
  echo "ibase=16; obase=2; ${a[3]}"  | bc -l 
done < infile
$ ./obase.shl
WS-2 100011 1101000101 1000110101
DT-3 1000101 10010100011 0
pp-2 1110110 1100000000 11100100

$

No time left --- I cannot fiddle with the remaining problem : 000 -> output as 000. fix that one yourself.

1 Like

See this might help you

awk  '
 
function bits2str(bits,        data, mask)
     {
         if (bits == 0)
             return "0"
     
         mask = 1
         for (; bits != 0; bits = rshift(bits, 1))
             data = (and(bits, mask) ? "1" : "0") data
     
         while ((length(data) % 8) != 0)
             data = "0" data
     
         return data
     }
     
     {for(i=2;i<=NF;i++)$i = bits2str(strtonum("0x"$i))}1' file

String Functions - The GNU Awk User's Guide

1 Like

0 instead of 000 output is ok

The simplest one-liner I could craft:

( echo ibase=16\; obase=2; awk '$1 = "\""$1"\n\""' OFS=\; file ) | bc | paste - - - -

Regards
Alister

Assuming 4 bits per nibble, I am missing something here.

Binary 23 is 00100011 and 345 is 0000001101000101 and 235 is 0000001000110101 ; where are the leading zeros? The OP requires a bit representation not a true hex to binary conversion.

The three zeros is in fact "0000000000000000" as a true hex to binary conversion.

If my assumption is wrong then ignore me...

It's not working on solaris but work on cygwin. how can I make it work on Solaris 10

On Solaris/SunOS system, change awk to /usr/xpg4/bin/awk , /usr/xpg6/bin/awk , or nawk , and try

Not working, This is the output:

/usr/xpg4/bin/awk: line 17 (NR=1): variable "" cannot be used as a function

Can you show what you have tried ? what is there in line 17 ?

/usr/xpg4/bin/awk  '
function bits2str(bits,        data, mask)
     {
         if (bits == 0)
             return "0"

         mask = 1
         for (; bits != 0; bits = rshift(bits, 1))
             data = (and(bits, mask) ? "1" : "0") data

         while ((length(data) % 1) != 0)
             data = "0" data

         return data
     }

     {for(i=5;i<=NF;i++)$i = bits2str(strtonum("0x"$i))}1' t.log

Okay, copy mystronum function from here Strtonum Function - The GNU Awk User's Guide, and try

Not working, same message

/usr/xpg4/bin/awk  '

function mystrtonum(str,        ret, chars, n, i, k, c)
     {
         if (str ~ /^0[0-7]*$/) {
             # octal
             n = length(str)
             ret = 0
             for (i = 1; i <= n; i++) {
                 c = substr(str, i, 1)
                 if ((k = index("01234567", c)) > 0)
                     k-- # adjust for 1-basing in awk
     
                 ret = ret * 8 + k
             }
         } else if (str ~ /^0[xX][[:xdigit:]]+/) {
             # hexadecimal
             str = substr(str, 3)    # lop off leading 0x
             n = length(str)
             ret = 0
             for (i = 1; i <= n; i++) {
                 c = substr(str, i, 1)
                 c = tolower(c)
                 if ((k = index("0123456789", c)) > 0)
                     k-- # adjust for 1-basing in awk
                 else if ((k = index("abcdef", c)) > 0)
                     k += 9
     
                 ret = ret * 16 + k
             }
         } else if (str ~ \
       /^[-+]?([0-9]+([.][0-9]*([Ee][0-9]+)?)?|([.][0-9]+([Ee][-+]?[0-9]+)?))$/) {
             # decimal number, possibly floating point
             ret = str + 0
         } else
             ret = "NOT-A-NUMBER"
     
         return ret
     }



function bits2str(bits,        data, mask)
     {
         if (bits == 0)
             return "0"

         mask = 1
         for (; bits != 0; bits = rshift(bits, 1))
             data = (and(bits, mask) ? "1" : "0") data

         while ((length(data) % 1) != 0)
             data = "0" data

         return data
     }

     {for(i=5;i<=NF;i++)$i = bits2str(mystrtonum("0x"$i))}1' t.log

Hi,
Just for fun, with sed:

$ cat htob.sed
h
s/[^ ]* //
s/0/XXXX/g
s/1/XXXY/g
s/2/XXYX/g
s/3/XXYY/g
s/4/XYXX/g
s/5/XYXY/g
s/6/XYYX/g
s/7/XYYY/g
s/8/YXXX/g
s/9/YXXY/g
s/A/YXYX/g
s/B/YXYY/g
s/C/YYXX/g
s/D/YYXY/g
s/E/YYYX/g
s/F/YYYY/g
y/XY/01/
x
s/ .*//
G
s/\n/ /
s/ 0*1/ 1/g
s/ 0* / 0 /g
s/ 0*$/ 0/g
$ cat filetoconv
WS-2 23 345 235
DT-3 45 4A3 000
pp-2 76 300 E4
$ sed -f htob.sed filetoconv
WS-2 100011 1101000101 1000110101
DT-3 1000101 10010100011 0
pp-2 1110110 1100000000 11100100

Regards.

1993 and later versions of the Korn shell give you some other options. On Solaris 10, /bin/ksh is based on ksh88, but I believe /usr/dt/bin/dtksh should work (although i don't currently have access to a system to verify it).

If the hexadecimal values you're trying to convert can be represented in a long in the programming model used by the shell on your system, the script:

#!/usr/dt/bin/dtksh
while read -A a
do      printf '%s' "${a[0]}"
        for ((i = 1; i < ${#a[@]}; i++))
        do
                typeset -i2  b=0x${a}

                printf " %s" ${b:2}
        done
        echo
done < Input

should do what you want. If you have arbitrarily long strings of hexadecimal digits, to convert to binary, I think the following script does what you want:

#!/usr/dt/bin/dtksh
typeset -A b b1
b1['0']='0';    b['0']='0000'
b1['1']='1';    b['1']='0001'
b1['2']='10';   b['2']='0010'
b1['3']='11';   b['3']='0011'
b1['4']='100';  b['4']='0100'
b1['5']='101';  b['5']='0101'
b1['6']='110';  b['6']='0110'
b1['7']='111';  b['7']='0111'
b1['8']='1000'; b['8']='1000'
b1['9']='1001'; b['9']='1001'
b1['A']='1010'; b['A']='1010'
b1['B']='1011'; b['B']='1011'
b1['C']='1100'; b['C']='1100'
b1['D']='1101'; b['D']='1101'
b1['E']='1110'; b['E']='1110'
b1['F']='1111'; b['F']='1111'
b1['a']='1010'; b['a']='1010'
b1['b']='1011'; b['b']='1011'
b1['c']='1100'; b['c']='1100'
b1['d']='1101'; b['d']='1101'
b1['e']='1110'; b['e']='1110'
b1['f']='1111'; b['f']='1111'
while read -A a
do      printf '%s' "${a[0]}"
        for ((i = 1; i < ${#a[@]}; i++))
        do      printf ' %s' "${b1[${a[$i]:0:1}]}"
                for ((j = 1; j < ${#a[$i]}; j++))
                do      printf '%s' "${b[${a[$i]:$j:1}]}"
                done
        done
        echo
done < Input

I used the file Input containing:

WS-2 23 345 235
DT-3 45 4A3 000
pp-2 76 300 E4
hex 10 21 32 43 54 65 76 87 98 A9 BA CB DC ED FE 0F AbCdEf1
hex2long 1234567890ABCDEFabcdef1234567890abcdefABCDEF

as a test case using /bin/ksh on OS X. The values show in red produced different results from these two scripts. The output produced by the 1st script above is:

WS-2 100011 1101000101 1000110101
DT-3 1000101 10010100011 0
pp-2 1110110 1100000000 11100100
hex 10000 100001 110010 1000011 1010100 1100101 1110110 10000111 10011000 10101001 10111010 11001011 11011100 11101101 11111110 1111 1010101111001101111011110001
hex2long 0

and the output produced by the 2nd script above is:

WS-2 100011 1101000101 1000110101
DT-3 1000101 10010100011 000000000
pp-2 1110110 1100000000 11100100
hex 10000 100001 110010 1000011 1010100 1100101 1110110 10000111 10011000 10101001 10111010 11001011 11011100 11101101 11111110 01111 1010101111001101111011110001
hex2long 10010001101000101011001111000100100001010101111001101111011111010101111001101111011110001001000110100010101100111100010010000101010111100110111101111101010111100110111101111