LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-03-2008, 11:07 AM   #1
genderbender
Member
 
Registered: Jan 2005
Location: US
Distribution: Centos, Ubuntu, Solaris, Redhat
Posts: 396

Rep: Reputation: 31
bash CIDR calculator


Been working on a code which will take my subnet mask and convert it into CIDR notation, I figured the best way to do it would be to convert each decimal bit to CIDR notation and then just replace the .'s between them with add and show the result. I'm a little stuck though, changing the numbers is proving a little... impossible. e.g 255 = 8 so 255.255.255.255 = 8+8+8+8 = 32, correct CIDR notation for that net mask.

Heres my code so far:
Code:
#!/bin/bash
#none of the below works...
255="8"
254="7"
252="6"
248="5"
240="4"
224="3"
192="2"
128="1"
0="0"
#I want to use the following code to get my netmask, i wrote this when I had no net tho.
#SN=`ifconfig ath0 | awk /'inet addr:'/'{print $4}'`
#Replaced it with this just for now...
echo -n "type subnet mask (255.255.255.255)"
read MASK
#following code will show 255+255+255+255
SN=`echo $MASK | tr '.' '+'`
echo $SN
So I need the math function to add it and a way of splitting the full address into 4 hex bits and thats about it oh and a forward slash at the end, eventual output needs to be /32.

Thanks so much

Last edited by genderbender; 06-03-2008 at 11:08 AM.
 
Old 06-03-2008, 01:07 PM   #2
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Code:
#!/bin/bash

# Function calculates number of bit in a netmask
#
mask2cidr() {
    nbits=0
    IFS=.
    for dec in $1 ; do
        case $dec in
            255) let nbits+=8;;
            254) let nbits+=7;;
            252) let nbits+=6;;
            248) let nbits+=5;;
            240) let nbits+=4;;
            224) let nbits+=3;;
            192) let nbits+=2;;
            128) let nbits+=1;;
            0);;
            *) echo "Error: $dec is not recognised"; exit 1
        esac
    done
    echo "$nbits"
}

## main ##
MASK=255.255.254.0
numbits=$(mask2cidr $MASK)
echo "/$numbits"
exit 0
 
Old 06-03-2008, 01:45 PM   #3
genderbender
Member
 
Registered: Jan 2005
Location: US
Distribution: Centos, Ubuntu, Solaris, Redhat
Posts: 396

Original Poster
Rep: Reputation: 31
Genius, thanks so much and a very elegant way of doing it, I really appreciate it.
 
Old 02-05-2009, 01:19 PM   #4
matschaffer
LQ Newbie
 
Registered: Feb 2009
Posts: 2

Rep: Reputation: 0
Incase any searchers happen to end up here, I also wrote the reverse (translate cidr to netmask) which I wasn't able to find anywhere.

Code:
cidr2mask() {
  local i mask=""
  local full_octets=$(($1/8))
  local partial_octet=$(($1%8))

  for ((i=0;i<4;i+=1)); do
    if [ $i -lt $full_octets ]; then
      mask+=255
    elif [ $i -eq $full_octets ]; then
      mask+=$((256 - 2**(8-$partial_octet)))
    else
      mask+=0
    fi  
    test $i -lt 3 && mask+=.
  done

  echo $mask
}
 
Old 02-05-2009, 06:47 PM   #5
jlinkels
LQ Guru
 
Registered: Oct 2003
Location: Bonaire, Leeuwarden
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,195

Rep: Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043Reputation: 1043
ipcalc does it all for you. (That is ipcalc, the bold spoils the 'i')

jlinkels
 
Old 02-06-2009, 08:05 AM   #6
matschaffer
LQ Newbie
 
Registered: Feb 2009
Posts: 2

Rep: Reputation: 0
Quote:
Originally Posted by jlinkels View Post
ipcalc does it all for you.
The only ipcalc I could google was an online tool. I (and probably the original poster) needed something easy in the context of a bash script. And it was also a fun little math problem

Thanks,
Mat
 
Old 02-04-2011, 09:16 AM   #7
r_hartman
LQ Newbie
 
Registered: Feb 2011
Location: Netherlands
Distribution: CentOS
Posts: 15

Rep: Reputation: 0
Quote:
Originally Posted by matschaffer View Post
The only ipcalc I could google was an online tool. I (and probably the original poster) needed something easy in the context of a bash script. And it was also a fun little math problem

Thanks,
Mat
ipcalc is part of the RedHat Enterprise Linux distribution, and possibly others.

But this thread inspired me to create a variation on ipcalc, ip4calc.sh, adapted and expanded from the bits of elegant code presented here. It can be downloaded from my website.

Edit: just noticed I can't link urls as this is my first post here.
Website is hac-maarssen.nl, take the Download link, download ip4calc.zip.

Have fun.
René
 
Old 02-05-2011, 02:48 AM   #8
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
Maybe something else to have a look at:
Code:
#!/usr/bin/awk -f

BEGIN {
    bits = 8
    for(x = 255; x >=0; x -= 2^i++)
        cidr[x] = bits--

    printf "Please enter current netmask: "
    getline netmask < "-"

    split(netmask, arr, "[.]")

    for(i = 1; i <= 4;i++)
        total += cidr[arr[i]]

    print total
}
 
Old 02-05-2011, 03:09 AM   #9
Tinkster
Moderator
 
Registered: Apr 2002
Location: earth
Distribution: slackware by choice, others too :} ... android.
Posts: 23,067
Blog Entries: 11

Rep: Reputation: 928Reputation: 928Reputation: 928Reputation: 928Reputation: 928Reputation: 928Reputation: 928Reputation: 928
Quote:
Originally Posted by r_hartman View Post
ipcalc is part of the RedHat Enterprise Linux distribution, and possibly others.

But this thread inspired me to create a variation on ipcalc, ip4calc.sh, adapted and expanded from the bits of elegant code presented here. It can be downloaded from my website.

Edit: just noticed I can't link urls as this is my first post here.
Website is hac-maarssen.nl, take the Download link, download ip4calc.zip.

Have fun.
René

Welcome to LQ,

And out of curiosity: why is your first post unearthing a 2 years gone
corpse of a thread?



Cheers,
Tink
 
Old 02-05-2011, 03:16 AM   #10
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
My bad ... didn't even look at the date
 
Old 02-05-2011, 04:34 AM   #11
genderbender
Member
 
Registered: Jan 2005
Location: US
Distribution: Centos, Ubuntu, Solaris, Redhat
Posts: 396

Original Poster
Rep: Reputation: 31
I'd like to delete this, the codes so (embaressingly) bad, there's not even any logic to it. Three years ago I must of been partially retarded.
 
Old 02-07-2011, 10:55 AM   #12
r_hartman
LQ Newbie
 
Registered: Feb 2011
Location: Netherlands
Distribution: CentOS
Posts: 15

Rep: Reputation: 0
@Tinkster
Thanks. I was actually looking for some code to calculate the CIDR network notation in bash, much like the OP, and this was the first hit that actually addressed my question, in many hits that were about on-line calculators. I thought the codes by Hko and MattShaffer were elegant, and from the thread I figured not all Linux/Unix flavors have ipcalc, suggested by jlinkels, shipped with them.

Hence my little exercise and returning my efforts to the community.
I did see the notice stating it was an old thread, but as it was about the only useful hit I got I thought it would be OK to add to it.

Cheers,
René

Last edited by r_hartman; 02-07-2011 at 10:58 AM.
 
Old 05-10-2013, 02:31 PM   #13
MPH426
LQ Newbie
 
Registered: Feb 2013
Posts: 23

Rep: Reputation: Disabled
I know this is a long dead horse but, I've got a big shovel and my nose doesn't work.

I just came across this. It was exactly what I was looking for. I didn't want to rely on ipcalc's availability.

The code posted by Hko works very well. The only problem is, it can give false results.

Once you hit an octet thats below 255 the following octets should be 0. In it's original form one could enter 255.252.224.252 (according the the code = /23 8^O) or any other combination producing false results. Come on, you know somebody will. LOL Adding the break statements fixes that.


Here is my "slight" revision

Code:
#!/bin/bash

# Function calculates number of bit in a netmask
#
mask2cidr() {
    nbits=0
    IFS=.
    for dec in $1 ; do
        case $dec in
            255) let nbits+=8;;
            254) let nbits+=7 ; break ;;
            252) let nbits+=6 ; break ;;
            248) let nbits+=5 ; break ;;
            240) let nbits+=4 ; break ;;
            224) let nbits+=3 ; break ;;
            192) let nbits+=2 ; break ;;
            128) let nbits+=1 ; break ;;
            0);;
            *) echo "Error: $dec is not recognised"; exit 1
        esac
    done
    echo "$nbits"
}

## main ##
# MASK=255.255.254.0
MASK=$1
numbits=$(mask2cidr $MASK)
echo "/$numbits"
exit 0
While I'm at it. Here's a couple of functions to calculate the network and broadcast addresses.

Note: Some versions of the bc caclulator don't come with bitwise functions.
Since I've been using the korn (ksh) shell since the late '80's and it's now public domain, I haven't tried too many others to see if they work.

Code:
#! /bin/ksh
###########################################################################
# netcalc:  Calculate the network address of a given IP address and mask.
###########################################################################
netcalc(){
  echo "$1" | sed -e 's/\./ /g' | read oct1 oct2 oct3 oct4
  echo "$2" | sed -e 's/\./ /g' | read msk1 msk2 msk3 msk4
  ipa=`echo $(($oct1 & $msk1))`
  ipb=`echo $(($oct2 & $msk2))`
  ipc=`echo $(($oct3 & $msk3))`
  ipd=`echo $(($oct4 & $msk4))`
  echo "$ipa.$ipb.$ipc.$ipd"
}
###########################################################################
# bcastcalc: Caclulate the broadcast address of a given IP address and mask.
###########################################################################
bcastcalc(){
  echo "$1" | sed -e 's/\./ /g' | read oct1 oct2 oct3 oct4
  echo "$2" | sed -e 's/\./ /g' | read msk1 msk2 msk3 msk4
  ipa=$(($oct1+(255-($oct1 | $msk1))))
  ipb=$(($oct2+(255-($oct2 | $msk2))))
  ipc=$(($oct3+(255-($oct3 | $msk3))))
  ipd=$(($oct4+(255-($oct4 | $msk4))))
  echo "$ipa.$ipb.$ipc.$ipd"
}
Hope it helps someone.
 
Old 05-12-2013, 04:04 PM   #14
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
Now that's the proper way to re-open a thread; making corrections and adding extra info.

Following that, here's a modification of the above function of my own. It's a bit shorter, but I couldn't say whether it's any more efficient.

Code:
#!/bin/bash

mask2cidr() {

    local nbits dec
    local -a octets=( [255]=8 [254]=7 [252]=6 [248]=5 [240]=4
                      [224]=3 [192]=2 [128]=1 [0]=''           )
    
    while read -rd '.' dec; do
        [[ -z ${octets[dec]} ]] && echo "Error: $dec is not recognised" && exit 1
        (( nbits += octets[dec] ))
        (( dec < 255 )) && break
    done <<<"$1."

    echo "/$nbits"

}

mask2cidr "$1"

exit 0
And here are my modified versions of the other functions as well. bash supports bitwise operations too, and only a few modifications are needed to convert from ksh (AFAICT, only the local command and the -a option to read aren't supported by ksh).

Code:
#!/bin/bash

netcalc(){

    local IFS='.' ip i
    local -a oct msk
	
    read -ra oct <<<"$1"
    read -ra msk <<<"$2"

    for i in ${!oct[@]}; do
        ip+=( "$(( oct[i] & msk[i] ))" )
    done
    
    echo "${ip[*]}"
}

bcastcalc(){

    local IFS='.' ip i
    local -a oct msk
	
    read -ra oct <<<"$1"
    read -ra msk <<<"$2"

    for i in ${!oct[@]}; do
        ip+=( "$(( oct[i] + ( 255 - ( oct[i] | msk[i] ) ) ))" )
    done

    echo "${ip[*]}"
}

netcalc "$1" "$2"
bcastcalc "$1" "$2"
One final caveat though. I'm not that experienced with ip stuff, so it's possible that I've made a conceptual mistake somewhere.

Last edited by David the H.; 05-12-2013 at 04:10 PM. Reason: small code corrections
 
Old 05-13-2013, 11:34 AM   #15
MPH426
LQ Newbie
 
Registered: Feb 2013
Posts: 23

Rep: Reputation: Disabled
David H.,

Awesome, very cool to see other ways of doing things. I lern't something new today. Just for kicks I converted it to ksh. I didn't know it could set arrays like that. Makes thinks MUCH easier when setting multi dimensional arrays.

You're right about the local not being supported in ksh, but for the read statement, just change -a to -A.

Here's ksh's version. Really not all that much different.
Code:
#!/bin/ksh

mask2cidr() {

  typeset -A octets=([255]=8 [254]=7 [252]=6 [248]=5 [240]=4
                     [224]=3 [192]=2 [128]=1 [0]=0)

  while read -rd '.' dec
  do
    [[ -z ${octets[$dec]} ]] && echo "Error: $dec is not recognised" && exit 1
    (( nbits += ${octets[$dec]} ))
    [[ $dec -lt 255 ]] && break
  done <<<"$1."

  echo "/$nbits"

}

mask2cidr "$1"

exit 0
Code:
#!/bin/ksh

netcalc(){
    IFS='.'
    typeset -A oct msk ip
    i=0

    read -rA oct <<<"$1"
    read -rA msk <<<"$2"

    while [ $i -lt "${#oct[@]}" ]
    do
      ip[$i]=$((oct[$i] & msk[$i]))
      i=$((i+1))
    done

    echo "IP: ${ip[*]}"
}

bcastcalc(){
    IFS='.' 
    typeset -A oct msk
    i=0

    read -rA oct <<<"$1"
    read -rA msk <<<"$2"

    while [ $i -lt "${#oct[@]}" ]
    do
      ip[$i]="$((oct[$i]+(255-(oct[$i] | msk[$i]))))"
      i=$((i+1))
    done

    echo "${ip[*]}"
}

netcalc "$1" "$2"
bcastcalc "$1" "$2"
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Understanding CIDR notation for iptables Madone_SL_5.5 Linux - Networking 5 12-07-2007 10:26 AM
IP calculator Blackmeth Slackware 7 08-13-2007 11:31 AM
C Calculator ChrisRain Programming 13 03-27-2007 02:33 AM
programming a calculator with bash xiekke Programming 4 03-18-2006 11:10 PM
A Calculator......... 320mb Programming 0 08-13-2004 04:55 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:33 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration