Search code examples
linuxshellbinaryhexinitrd

How to convert a sequence of bits (bitmask) into the corresponding hex number


Let's say I have the bitmask 1000000000. I would like to convert it to its equivalent hexadecimal number, i.e. 0x200 (specifically, I only want the 200 part, but that's easy to take care of)

I know I can do this in Python or using various bash features and functions. Examples:

python -c "print format(0b1000000000, 'x')"
200

printf '%x\n' "$((2#1000000000))"
200

echo 'ibase=2;obase=10000;1000000000'|bc
200

But, I wanna do this using only functions available in sh (i.e. Shell, not Bash). More specifically, I want it to work with sh in an initrd image that I'm putting together. AFAIK, none of the examples above would work in an initramfs / busybox context.


Solution

  • It seems busybox sh has enough features ("substring" parameter substitution and arithmetic evaluation) to be useful enough for this:

    $ busybox sh
    
    
    BusyBox v1.22.1 (Ubuntu 1:1.22.0-15ubuntu1) built-in shell (ash)
    Enter 'help' for a list of built-in commands.
    
    ~ $ bitstr=1000000000
    ~ $ n=0
    ~ $ i=0
    ~ $ while [ $i -lt ${#bitstr} ]; do
    > n=$(( 2*n + ${bitstr:$i:1} ))
    > i=$((i+1))
    > done
    ~ $ echo $n
    512
    ~ $ printf "%x\n" $n
    200
    

    Encapsulate into a function:

    b2h() {
      local bitstr=$1 n=0 i=0
      while [ $i -lt ${#bitstr} ]; do
        n=$(( 2*n + ${bitstr:$i:1} ))
        i=$(( i + 1 ))
      done
      printf "%x\n" "$n"
    }
    b2h 1000000000   # => 200