Bash Script : Bitwise Not Operation in bash


This is a post to present one method to inverse the bit pattern of an input number, the bitwise not operation on a bit pattern. I am presenting one method which i figured out.

The Idea

We first take a bitstring from the user and store it into a shell variable. Then we manually scan each bit of this binary string and inspecting the value of the currently scanned bit symbol (0 or 1) we make another string with the opposite bit symbol at that position. At the end of the bit string scanning the second shell variable would contain the inverted bit pattern of the bit string. The implementation is shown below.

Sourcecode

#!/bin/bash

num=$1

if [ -z $num ]
 then
   echo "$0 <number_in_decimal>"
   echo "Output would be the 1's compliment of the input"
   exit
fi

i=0
flag=1

inv_bit=""
curr_bit=0

while [ true ]
 do
  curr_bit=${num:$i:1}

  if [ -z $curr_bit ]
   then
    break
  fi

  if [ $curr_bit -eq 0 ]
   then
    inv_bit=${inv_bit}1
  elif [ $curr_bit -eq 1 ]
   then
    inv_bit=${inv_bit}0
  else
    flag=0
    break
  fi

  i=$((i+1))
done

if [ $flag -eq 1 ]
 then
  echo "~$num is $inv_bit"
else
  echo "Invalid input"
fi

Description

First there is a minimal error checking which only allow if some non-zero string is provided in the command line. The input number from command line is taken into the shell variable num. The flag indicates if the inverted bit string complement output is valid and initially it is set to 1 indicating valid. The inverted bit pattern would be stored into the shell variable inv_bit which is initialized as empty string. The curr_bit would be used to hold the currently scanned bit position of the num. i is initialized to zero, which would be used to index into the num bit positions. Please note that the binary bit pattern is scanned as a string from left to right (index 0 starts at the leftmost position).

The while loop is entered. Starting from 0, at each iteration the ith bit from num is cut out by bash builtin shell substitution syntax ${num:$i:1} where $i is the base and 1 is the offset of the substring to be cut out from num. In effect it gets the ith character of the string and saves into curr_bit .

If curr_bit is a zero string, then num has no more bits to be scanned and the process finishes. If curr_bit is 1 then we append 0 to the current value inv_bit, and if curr_bit is 0 then we need to append 1 to the current value of inv_bit. Any other symbol for curr_bit sets the flag=0 and ends the process. To append the found bit into the existing inverse bit pattern we do inv_bit=${inv_bit}0 and inv_bit=${inv_bit}1 as needed. This appends the newly found inverted bit at the end of the intermediate result stored in inv_bit . The index i is incremented.

After the loop breaks (when the curr_bit becomes zero string), if flag is 1 , then the inverse bit of the input bit pattern is output, or an error message is printed otherwise.

Output

Here are some sample output:

[phoxis@localhost disk]$ ./inv_1.sh 1010
~1010 is 0101
[phoxis@localhost disk]$ ./inv_1.sh 1101
~1101 is 0010
[phoxis@localhost disk]$ ./inv_1.sh 1111
~1111 is 0000
[phoxis@localhost disk]$ ./inv_1.sh 11010010
~11010010 is 00101101
[phoxis@localhost disk]$ ./inv_1.sh 10010011010011
~10010011010011 is 01101100101100
[phoxis@localhost disk]$ ./inv_1.sh 110212
Invalid input

Fixed Length Bit String

To find a one’s complement of an integer with this method, then we need to fix the length of the bitpattern, and consider the MSB as the signed bit. This can be implemented by doing a minor modification to the above script which is as follows. We can make the while loop run a fixed number of times, say 32 times for to find the one’s complement of a 32bit integer. While the input string does not end like the above process we will append the opposite bit in the destination inverse bit pattern variable. When the input number has ended ie. the curr_bit is a zero string and i is still not 32, then we need to prepend 1s to the inverted bit string calculated till now. This is done by placing the 1 before the inv_bit like inv_bit=1$inv_bit . The modified script is shown below:

#!/bin/bash

num=$1

if [ -z $num ]
 then
   echo "$0 <number_in_decimal>"
   echo "Output would be the 1's compliment of the input"
   exit
fi

i=0
flag=1

inv_bit=""
curr_bit=0

while [ $i -lt 32 ]
 do
  curr_bit=${num:$i:1}


  if [ -z $curr_bit ]
   then
    inv_bit=1$inv_bit
  elif [ $curr_bit -eq 0 ]
   then
    inv_bit=${inv_bit}1
  elif [ $curr_bit -eq 1 ]
   then
    inv_bit=${inv_bit}0
  else
    flag=0
    break
  fi

  i=$((i+1))
done

if [ $flag -eq 1 ]
 then
  echo "~$num is $inv_bit"
else
  echo "Invalid input"
fi

Output

Here is some sample output of this code

[phoxis@localhost disk]$ ./inv_2.sh 1010
~1010 is 11111111111111111111111111110101
[phoxis@localhost disk]$ ./inv_2.sh 10001101001
~10001101001 is 11111111111111111111101110010110
[phoxis@localhost disk]$ ./inv_2.sh 11111111111111111111111111101101
~11111111111111111111111111101101 is 00000000000000000000000000010010

Comments

We can accept any other base integers and first convert it into binary bit pattern with bc and then apply the above module(s).

About these ads

About phoxis

Homo-sapiens
This entry was posted in Computer Science, Linux / Unix Shell and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s