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
Was it helpful?

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top