ProgrammingThis 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.
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.
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.
#!/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
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
}
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
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.
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?
@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.
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"
}
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
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"
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.