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 |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
 |
|
06-03-2008, 12:07 PM
|
#1
|
Member
Registered: Jan 2005
Location: US
Distribution: Centos, Ubuntu, Solaris, Redhat
Posts: 396
Rep:
|
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 12:08 PM.
|
|
|
06-03-2008, 02:07 PM
|
#2
|
Senior Member
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536
Rep: 
|
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
|
|
|
06-03-2008, 02:45 PM
|
#3
|
Member
Registered: Jan 2005
Location: US
Distribution: Centos, Ubuntu, Solaris, Redhat
Posts: 396
Original Poster
Rep:
|
Genius, thanks so much and a very elegant way of doing it, I really appreciate it.
|
|
|
02-05-2009, 02:19 PM
|
#4
|
LQ Newbie
Registered: Feb 2009
Posts: 2
Rep:
|
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
}
|
|
|
02-05-2009, 07:47 PM
|
#5
|
LQ Guru
Registered: Oct 2003
Location: Bonaire, Leeuwarden
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,196
|
ipcalc does it all for you. (That is ipcalc, the bold spoils the 'i')
jlinkels
|
|
|
02-06-2009, 09:05 AM
|
#6
|
LQ Newbie
Registered: Feb 2009
Posts: 2
Rep:
|
Quote:
Originally Posted by jlinkels
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
|
|
|
02-04-2011, 10:16 AM
|
#7
|
LQ Newbie
Registered: Feb 2011
Location: Netherlands
Distribution: CentOS
Posts: 15
Rep:
|
Quote:
Originally Posted by matschaffer
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é
|
|
|
02-05-2011, 03:48 AM
|
#8
|
LQ Guru
Registered: Sep 2009
Location: Perth
Distribution: Arch
Posts: 10,031
|
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
}
|
|
|
02-05-2011, 04:09 AM
|
#9
|
Moderator
Registered: Apr 2002
Location: earth
Distribution: slackware by choice, others too :} ... android.
Posts: 23,067
|
Quote:
Originally Posted by r_hartman
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
|
|
|
02-05-2011, 04:16 AM
|
#10
|
LQ Guru
Registered: Sep 2009
Location: Perth
Distribution: Arch
Posts: 10,031
|
My bad ... didn't even look at the date 
|
|
|
02-05-2011, 05:34 AM
|
#11
|
Member
Registered: Jan 2005
Location: US
Distribution: Centos, Ubuntu, Solaris, Redhat
Posts: 396
Original Poster
Rep:
|
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.
|
|
|
02-07-2011, 11:55 AM
|
#12
|
LQ Newbie
Registered: Feb 2011
Location: Netherlands
Distribution: CentOS
Posts: 15
Rep:
|
@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 11:58 AM.
|
|
|
05-10-2013, 03:31 PM
|
#13
|
LQ Newbie
Registered: Feb 2013
Posts: 23
Rep: 
|
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.
|
|
|
05-12-2013, 05:04 PM
|
#14
|
Bash Guru
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852
|
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 05:10 PM.
Reason: small code corrections
|
|
|
05-13-2013, 12:34 PM
|
#15
|
LQ Newbie
Registered: Feb 2013
Posts: 23
Rep: 
|
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"
|
|
|
All times are GMT -5. The time now is 01:39 AM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|