Validating an IP Address in a Bash Script
June 26th, 2008 by Mitch Frazier in
I've recently written about using bash arrays and bash regular expressions, so here's a more useful example of using them to test IP addresses for validity.
To belabor the obvious: IP addresses are 32 bit values written as four numbers (the individual bytes of the IP address) separated by dots (periods). Each of the four numbers has a valid range of 0 to 255.
The following bash script contains a bash function which returns true if it is passed a valid IP address and false otherwise. In bash speak true means it exits with a zero status, anything else is false. The status of a command/function is stored in the bash variable "$?".
#!/bin/bash
# Test an IP address for validity:
# Usage:
# valid_ip IP_ADDRESS
# if [[ $? -eq 0 ]]; then echo good; else echo bad; fi
# OR
# if valid_ip IP_ADDRESS; then echo good; else echo bad; fi
#
function valid_ip()
{
local ip=$1
local stat=1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
OIFS=$IFS
IFS='.'
ip=($ip)
IFS=$OIFS
[[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
&& ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
stat=$?
fi
return $stat
}
# If run directly, execute some tests.
if [[ "$(basename $0 .sh)" == 'valid_ip' ]]; then
ips='
4.2.2.2
a.b.c.d
192.168.1.1
0.0.0.0
255.255.255.255
255.255.255.256
192.168.0.1
192.168.0
1234.123.123.123
'
for ip in $ips
do
if valid_ip $ip; then stat='good'; else stat='bad'; fi
printf "%-20s: %s\n" "$ip" "$stat"
done
fi
If you save this script as "valid_ip.sh" and then run it directly it will run some tests and prints the results:
# sh valid_ip.sh 4.2.2.2 : good a.b.c.d : bad 192.168.1.1 : good 0.0.0.0 : good 255.255.255.255 : good 255.255.255.256 : bad 192.168.0.1 : good 192.168.0 : bad 1234.123.123.123 : bad
In the function valid_ip, the if statement uses a regular expression to make sure the subject IP address consists of four dot separated numbers:
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
If that test passes then the code inside the if statement
separates the subject IP address into four parts at the dots and places the parts in an array:
OIFS=$IFS IFS='.' ip=($ip) IFS=$OIFSIt does this by momentarily changing bash's Internal Field Separator variable so that rather than parsing words as whitespace separated items, bash parses them as dot separated. Putting the value of the subject IP address inside parenthesis and assigning it to itself thereby turns it into an array where each dot separated number is assigned to an array slot. Now the individual pieces are tested to make sure they're all less than or equal to 255 and the status of the test is saved so that it can be returned to the caller:
[[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
&& ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
stat=$?
Note that there's no need to test that the numbers are greater than or equal to zero
because the regular expression test has already eliminated any thing that doesn't
consist of only dots and digits.
__________________________
Mitch Frazier is the System Administrator at Linux Journal.
Special Magazine Offer -- 2 Free Trial Issues!
Receive 2 free trial issues of Linux Journal as well as instant online access to current and past issues. There's NO RISK and NO OBLIGATION to buy. CLICK HERE for offer
Linux Journal: delivering readers the advice and inspiration they need to get the most out of their Linux systems since 1994.
Sorry, offer available in the US only. International orders, click here.
Subscribe now!
The Latest
Featured Videos
In case you were wondering about the fun side of Linux World Expo, we thought we'd give you a peek at our shenanigans. We at Linux Journal love what we do so much, that we can't help but have a ball wherever we go.
The X Window System is a magnificent platform for many uses, but using it to run an application over a slow network is nearly impossible. This is an introduction to NX, a technology that makes remote applications fly even over commodity internet.
Recently Popular
From the Magazine
September 2008, #173
Feeling a bit like a Thermian? Never give up, never surrender! Someday, you could go from underdog to top dog. Just take a look at a few of the underdogs we highlight in this issue: Mutt, djbdns, Nginix, Gentoo, Xara and the program voted mostly likely to fail just a few years back—Firefox. If Firefox not radical enough for you, check out Chef Marcel's column for some more alternatives. Having trouble mapping your program data to your relational database? If so, Rueven Lerner shows you some tricks in his At The Forge column.
Need to run GUI applications on your server in the next state? In his Paranoid Penguin column, Mick Bauer shows you how to do it securely. Kyle Rankin keeps hacking and slashing and shows you a few split screen secrets you may not be familiar with. Finally, we all know what happens next February, but only Doc knows what happens afterward.
Delicious
Digg
Reddit
Newsvine
Technorati







Not the bash I know
On July 9th, 2008 Anonymous (not verified) says:
I tried this with bash, since I wasn't aware that bash supported regular expressions, and it fell over when it encountered '=~', since it didn't know wnything about regular expressions.
What version of bash was this written with?
Version 3
On July 10th, 2008 Mitch Frazier says:
Regular expressions have been part of bash since version 3 arrived on July 27, 2004. Specifically, I have version 3.1.17.
__________________________Mitch Frazier is the System Administrator at Linux Journal.
Re: Validating an IP Address
On July 4th, 2008 John W. Krahn (not verified) says:
Actually an IP address doesn't have to be in the dotted quad format to work correctly, it depends on where you use it:
$ perl -MSocket -le'print inet_ntoa inet_aton q/www.linuxjournal.com/'
66.240.243.113
$ perl -MSocket -le'print unpack q/N/, inet_aton q/66.240.243.113/'
1123087217
$ ping 1123087217
PING 1123087217 (66.240.243.113) 56(84) bytes of data.
64 bytes from 66.240.243.113: icmp_seq=1 ttl=52 time=72.6 ms
64 bytes from 66.240.243.113: icmp_seq=2 ttl=52 time=66.7 ms
64 bytes from 66.240.243.113: icmp_seq=3 ttl=52 time=66.7 ms
--- 1123087217 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 66.702/68.711/72.667/2.813 ms
$ traceroute 1123087217
traceroute to 1123087217 (66.240.243.113), 30 hops max, 40 byte packets
1 * * *
2 ... etc.
$ perl -MSocket -le'print unpack q/N/, inet_aton q/0.240.243.113/'
15790961
$ ping 66.15790961
PING 66.15790961 (66.240.243.113) 56(84) bytes of data.
64 bytes from 66.240.243.113: icmp_seq=1 ttl=52 time=104 ms
64 bytes from 66.240.243.113: icmp_seq=2 ttl=52 time=99.8 ms
--- 66.15790961 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 99.822/102.097/104.372/2.275 ms
$ perl -MSocket -le'print unpack q/N/, inet_aton q/0.0.243.113/'
62321
$ ping 66.240.62321
PING 66.240.62321 (66.240.243.113) 56(84) bytes of data.
64 bytes from 66.240.243.113: icmp_seq=1 ttl=52 time=65.0 ms
64 bytes from 66.240.243.113: icmp_seq=2 ttl=52 time=93.5 ms
64 bytes from 66.240.243.113: icmp_seq=3 ttl=52 time=66.0 ms
--- 66.240.62321 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 65.090/74.920/93.578/13.202 ms
Dash Support
On June 29th, 2008 Anonymous (not verified) says:
Good but does not run using dash!!
I don't think dash supports the regex in compound expressions and doesn't support the function keyword and [[]] parenthesis.
Probably not
On July 1st, 2008 Mitch Frazier says:
Only tested it with bash, nothing else.
__________________________Mitch Frazier is the System Administrator at Linux Journal.
What about IPv6 addresses?
On June 26th, 2008 Timmy Jose (not verified) says:
This does not handle IPv6 addresses which is a much more trickier gambit. And a combination of IPv4/ IPv6 addresses would indeed make things interesting. Add the mundane alphanumeric DNS names and you have a real stew of messy, unpredicatable code! ;-)
As They Say
On July 1st, 2008 Mitch Frazier says:
That's left as an exercise for the reader.
__________________________Mitch Frazier is the System Administrator at Linux Journal.