Validate an ip in dash (not bash)
-
29-04-2021 - |
Question
I am trying to validate an ip address within a dash script. I've found many ways to achieve the same with bash such as in linuxjournal
Basically what is does is a comparision using this:
if [[ $ip =~ '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' ]]; then
do something
fi
Is there any way to get the same with dash?
UPDATE: This is the final script that does what I needed:
#In case RANGE is a network range (cidr notation) it's splitted to every ip from
# that range, otherwise we just keep the ip
if echo $RANGE | grep -E -q '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}$'; then
IPS=`prips $RANGE -e ...0,255`
if [ "$?" != "0" ] ; then
echo "ERROR: Not a valid network range!"
exit 1
fi
elif echo $RANGE | grep -E -q '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then
IPS="$RANGE"
else
echo "$RANGE no is not a valid IP address or network range"
exit 1
fi
Solution
Assuming you are happy with the validation string:
$ s='[0-9]\{1,3\}' $ echo $ip | grep > /dev/null "^$s\.$s\.$s\.$s$" && echo $ip is valid
Note that this accepts invalid ip addresses like 876.3.4.5
To validate an ip, it's really not convenient to use a regular expression. A relative easy thing to do is:
IFS=. read a b c d << EOF $ip EOF if ( for i in a b c d; do eval test \$$i -gt 0 && eval test \$$i -le 255 || exit 1 done 2> /dev/null ) then echo $ip is valid fi
OTHER TIPS
You can build a case
statement, although it will be more verbose than a regex. On the other hand, you avoid spawning any external processes, and it might be easier to read and maintain to boot.
if case $ip in
# Invalid if it contains any character other than number or dot
# Invalid if it contains more than three dots
# Invalid if it contains two adjacent dots
# Invalid if it begins with a non-number
# Invalid if it ends with a non-number
*[!.0-9]* | *.*.*.*.* | *..* | [!0-9]* | *[!0-9] ) false ;;
# Invalid if it contains a number bigger than 255:
# 256-259 or 260-299 or 300-999 or four adjacent digits
*25[6-9]* | *2[6-9][0-9]* | *[3-9][0-9][0-9]* | *[0-9][0-9][0-9][0-9]* ) false;;
# Verify that it contains three dots
*.*.*.* ) true ;;
# Failing that, invalid after all (too few dots)
*) false ;;
esac; then
echo "$ip" is valid
fi
Notice the funky use of a case
statement (returning either true or false) as the condition in an if
statement.
This is slightly stricter than the regex in that it requires each octet to be less than 256.
Here is a small dash
shell function which does not use any external commands and that checks if an IPv4 address is valid. It returns true if the address was correctly formatted, false otherwise.
I've tried to explain the magic in my comments.
valid_ip() {
local IP="$1" IFS="." PART # make vars local, get arg, set $IFS
set -- $IP # split on $IFS, set $1, $2 etc.
[ "$#" != 4 ] && return 1 # BAD: if not 4 parts
for PART; do # loop over $1, $2 etc.
case "$PART" in
*[!0-9]*) return 1 # BAD: if $PART contains non-digit
esac
[ "$PART" -gt 255 ] && return 1 # BAD: if $PART > 255
done
return 0 # GOOD: nothing bad found
}
With this function you can test your IP address, e.g. to abort your script if the IP address is invalid:
if valid_ip "$IP"; then
echo "ERROR: IP address '$IP' is invalid" >&2
exit 4
fi