Question

I am working on a script which does subnet calculations. So far, it looks like this (in part):

echo "Subnet Address  : "$sn1.$sn2.$sn3.$sn4
echo "BCast Address   : "$br1.$br2.$br3.$br4
echo -e "\nSubnet address in binary" :
echo "obase=2;$ip1"+"obase=2;$ip2"+"obase=2;$ip3"+"obase=2;$ip4" \
  | bc | awk '{printf("%08d",$ip1)}'
echo -e "\nBroadcast address in binary" :
echo "obase=2;$br1"+"obase=2;$br2"+"obase=2;$br3"+"obase=2;$br4" \
  | bc | awk '{printf("%08d",$br1)}'

which gives me this output:

Subnet address in binary :
11000010101010100000001100000000
Broadcast address in binary :
11000010101010100000001100011111
  1. I tried '{printf("%08d.",$br1)}' and '{printf(".%08d",$br1)}' to separate the octets but I get an extra dot on the beginning or at the end.
  2. I want to calculate how many aces the netmask has, but I really cant find a way to get the output of the echo "obase=2;$br1"+"obase=2;$br2"+"obase=2;$br3"+"obase=2;$br4"| bc | awk to a string so I can count them.

Any suggestions?

Was it helpful?

Solution 2

To separate the octets I would use printf and paste instead, e.g.:

ip1=127; ip2=0; ip3=0; ip4=1
printf "%08d\n" $(bc <<<"obase=2; $ip1; $ip2; $ip3; $ip4") | paste -sd.

Or if the ip is in one variable:

ip=127.0.0.1
printf "%08d\n" $(bc <<<"obase=2; ${ip//./;}") | paste -sd.

Output:

00001010.00101010.01100110.11111100

To count the number of 1s in a netmask just add them:

netmask=255.255.255.252
printf "%08d" $(bc <<<"obase=2; ${netmask//./;}") | grep -o . | paste -sd+ | bc

Output:

30

OTHER TIPS

So you want the output to be in the format of: 01111111.00000000.00000000.00000001?

Well, the cheat method, I used when I banged my head against this was to wrap around ipcalc:

%ipcalc 127.0.0.1
Address:   127.0.0.1            01111111.00000000.00000000. 00000001
Netmask:   255.255.255.0 = 24   11111111.11111111.11111111. 00000000
Wildcard:  0.0.0.255            00000000.00000000.00000000. 11111111
=>
Network:   127.0.0.0/24         01111111.00000000.00000000. 00000000
HostMin:   127.0.0.1            01111111.00000000.00000000. 00000001
HostMax:   127.0.0.254          01111111.00000000.00000000. 11111110
Broadcast: 127.0.0.255          01111111.00000000.00000000. 11111111
Hosts/Net: 254                   Class A, Loopback

And then extract what I needed. Runs MUCH faster than parsing multiple times through 'bc'. Ie, no sense re-inventing the wheel if you don't need to.

If you do feel like re-inventing the wheel a bit:

$ echo "obase=2;200" + "obase=2;150" + "obase=2;200" + "obase=2;150" | \
   bc | awk '{printf "%08d\." ,$1}' | \
   sed -e 's/[.]*$//'
11001010.10011000.11001010.10010110

That will get you the 8 digit binary output format you want.

Two quick solutions:

$ echo $br1.$br2.$br3.$br4 |  
    perl -F\\\. -anE 'say join ".", map { sprintf "%08b", $_ } @F'
$ perl -e 'printf( "%08b.%08b.%08b.%08b\n", '$br1,$br2,$br3,$br4')'
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top