# KSH93 Bit Manipulation

When programmers think about bitwise manipulation, they usually think about using C or C++ to solve their problem since both programming languages provide a rich set of features which make it easy to perform bitwise manipulation.

However it is possible to just as easily perform such operations using the ksh93 shell.  This post will explain what bitwise manipulation and number conversion facilities are available in ksh93 and provide some hopefully useful utilities and examples.

Many programmers are unaware that ksh93 has builtin support for different numeral radices (AKA arithmetic bases) as shown in the following example.

```\$ print \$(( 10 + 20 ))
30
\$ print \$(( 2#10 + 20 ))
22
\$ print \$(( 2#10 + 4#20 ))
10
\$```

where base 2 is denoted by 2#, base 4 by #4 and so on.  The general case syntax is [base#]n where base is a decimal number between 2 and 36 representing the arithmetic base and n is a number in that base.  You can mix and match bases within expressions.  As you would expect, the default base, i.e. if [base#] is omitted, is decimal(10).

Here is an example of how to convert decimal 255 to base 2, base 8 and base 16 respectively using the typeset command.

```\$ typeset -i2 a=255
\$ echo \$a
2#11111111
\$ typeset -i8 a=255
\$ echo \$a
8#377
\$ typeset -i16 a=255
\$ echo \$a
16#ff
\$```

Note that ksh93 displays the base prefix before each number unless it is a decimal number, i.e. base 10.

The bitwise manipulation operators in ksh93 are AND, OR, XOR, SHIFT LEFT and SHIFT RIGHT.  There are no SHIFT ROTATE or COMPLEMENT operators.  The following is the list of supported bitwise operators in decreasing order of precedence which, by the way, is the same as in the C programming language.

 << >> Bitwise shift left, shift right & Bitwise AND ^ Bitwise XOR | Bitwise OR

The following shell script includes both logical and bitwise operators together with the expected output for each statement.  Notice the difference in output between a logical and bitwise operator.

```#!/bin/ksh93

integer -i2 a=5
integer -i2 b=6

# expected output 1
print \$(( a < b ))
# expected output 0
print \$(( a > b ))
# expected output 3
print \$(( a ^ b ))
# expected output 4
print \$(( a & b ))
# expected output 1
print \$(( a && b ))
# expected output 7
print \$(( a | b ))
# expected output 1
print \$(( a || b ))```

A useful feature of bitwise operators is that by using the shift left and shift right bitwise operators you can mimic multiplication or division by 2 or a power of 2.

```\$ x=4
\$ print \$((x << 1))
8
\$ print \$(( x << 2 ))
16
\$ print \$(( x >> 1 ))
2
\$ print \$(( x >> 2 ))
1```

Here is a fairly simple shell script which uses numeric base conversion and bitwise operators to calculate the network and broadcast addresses for a given IP address and subnet mask.\

```#!/bin/ksh93

[[ \$# != 2 ]] && {
exit 1
}

SaveIFS=\$IFS
IFS=.
typeset -a IParr=(\$1)
typeset -a NMarr=(\$2)
IFS=\$SaveIFS

typeset -i2 ip1=\${IParr}
typeset -i2 ip2=\${IParr}
typeset -i2 ip3=\${IParr}
typeset -i2 ip4=\${IParr}

typeset -i2 nm1=\${NMarr}
typeset -i2 nm2=\${NMarr}
typeset -i2 nm3=\${NMarr}
typeset -i2 nm4=\${NMarr}

echo
echo "  Network Address: \$((ip1 & nm1)).\$((ip2 & nm2)).\$((ip3 & nm3)).\$((ip4 & nm4))"
echo

exit 0
```

Some sample output for this script.

```\$ ./calculate-address 10.150.12.1 255.255.255.0

The next example calculates the network and broadcast addresses for a Classless Inter-Domain Routing (CIDR) compliant IP address.  Note the use of the shift right operator in calculating the network mask.

```#!/bin/ksh93

[[ \$# != 1 ]] && {
exit 1
}

SaveIFS=\$IFS
IFS="./"
typeset -a IParr=(\$1)
IFS=\$SaveIFS

typeset -i2 ip1=\${IParr}
typeset -i2 ip2=\${IParr}
typeset -i2 ip3=\${IParr}
typeset -i2 ip4=\${IParr}
typeset -i2 cidr=\${IParr}

typeset -i2 nm1=0 nm2=0 nm3=0 nm4=0

typeset -i quad=\$(( cidr / 8 ))
sigbits=\$(( cidr % 8 ))
if (( sigbits != 0 )); then
slot=\$(( 256 - ( 256 >> \$sigbits ) ))
fi

for (( i=1; i < 5; i++ ))
do
nameref nm=nm\${i}
if (( quad != 0 )); then
nm=255
elif (( quad == 0 )); then
nm=slot
break
fi
done

print
print " CIDR Network (Route): \$((ip1 & nm1)).\$((ip2 & nm2)).\$((ip3 & nm3)).\$((ip4 & nm4))"
m4)))"
print

exit 0
```

Sample output:

```\$ ./calculate-address "192.168.21.12/18"

CIDR Network (Route): 192.168.0.0

For my example, suppose you are given a hexadecimal string 3AF9:3B01 and you want to expand that string to produce a list of all the values between 3AF9 and 3B01. The wrinkle is that you want all letters in the hexadecimal numbers to be uppercased.

```#!/bin/ksh93

x=3AF9:3B01

typeset -i16 a=0x\${x%:*}
typeset -i16 b=0x\${x#*:}
typeset -u c

for (( ; a <= b; a++ ))
do
c=\${a:3}
echo "\$c"
done
```

Here is the output:

```\$ ./hexlist
3AF9
3AFA
3AFB
3AFC
3AFD
3AFE
3AFF
3B00
3B01```

Here is another interesting example of using bit arithmetic to solve a problem. In this particular case, the user wanted to have a shell script which accepted a 32-bit hexadecimal number as input and assigns consecutive blocks of 4 bits of the equivalent binary number to each of 8 variables.

```#!/bin/ksh93

integer -i2 v0 v1 v2 v3 v4 v5 v6 v7

read hn?"Enter a 32-bit hex decimal number: "
integer -i2 in=16#\$hn

for ((i=0; i < 8; i++))
do
nameref var=v\${i}
var=\$(( ((in << (i*4)) & mask) >> 28 ))
done

printf "%032.0.2d\n" \$in
printf "%04.0.2d %04.0.2d %04.0.2d %04.0.2d %04.0.2d %04.0.2d %04.0.2d %04.0.2d\n" \
\$v0 \$v1 \$v2 \$v3 \$v4 \$v5 \$v6 \$v7
```

Note the use of a third specifier with %d. In ksh93, each of the integral format specifiers can have a third modifier after width and precision that specifies the base of the conversion from 2 to 64. In addition the use of the # modifier as the third specifier will cause base# to be prepended to the value.

Here is sample output for this script:

```\$ ./hexblock
Enter a 32-bit hex decimal number: abcdabcd
10101011110011011010101111001101
1010 1011 1100 1101 1010 1011 1100 1101
\$ ./hexblock
Enter a 32-bit hex decimal number: AFC92317
10101111110010010010001100010111
1010 1111 1100 1001 0010 0011 0001 0111```

Suppose instead that you wanted to store the individual bits in an array. Here is one way to do this is:

```#!/bin/ksh93

read num?"Enter binary 32 bit number: "

integer -i2 a=2#\$num

typeset -ui barray=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)

for (( i=0; i < 32; i++, mask=\$(( mask << 1)) ))
do
nameref var=barray[\$i]
(( \$mask & \$a )) &&  var=1
done

# how to test the array values
if (( \${barray} ))
then
echo "barray is 1"
else
echo "barray is 0"
fi
```

This example calculates the binary and decimal equivalent of an IP address:

```#!/bin/ksh93

[[ \$# != 1 ]] && {
exit 1
}

SaveIFS=\$IFS
IFS="."
typeset -a IParr=(\$1)
IFS=\$SaveIFS

typeset -i2 ip1=\${IParr}
typeset -i2 ip2=\${IParr}
typeset -i2 ip3=\${IParr}
typeset -i2 ip4=\${IParr}

typeset -ui2 d=\$(( (ip1 << 24) | (ip2 << 16) | (ip3 << 8) | ip4 ))

print "   Binary equivalent: \$d"
print "  Decimal equivalent: \$((d))"

exit 0
```

Here is sample output:

```\$ ./example 172.16.120.100