2

I'm making a script that validate an IP address. I do this:

read pool
checkIp()
{
    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
}

checkIp $pool
if [ $? -eq 0 ]
    then
        echo "valid"
    else
        echo "invalid"
fi

The problem is that now the requirement is to valid that from the 2nd octet the input can contain the wildcard "*" (i think is better to use CIDR notation but is not the case), and now i can't use -le because if there is not a number, it fails.

I'd tried some forms but all conversions fails.

  • Not really into network addressing. Is “1.2.*.4” valid (my answer allows it), or as soon a “” is encountered the remaining pieces have to also be “”s? – manatwork Jan 30 '13 at 14:23
  • The remaining spaces should be "*"... – X3MBoy Jan 30 '13 at 15:18
  • Note that allowing 010.010.010.010 could cause confusion as most applications and library functions (gethostbyname, inet_addr...) consider it the same as 8.8.8.8 while some other the same as 10.10.10.10 (inet_pton). – Stéphane Chazelas Jan 30 '13 at 15:27
3

With a little additional rewrite. (As you use Bash-specific regular expression, just populate the BASH_REMATCH array instead of manipulating a word splitting.)

checkIp()
{
  local ip="$1"

  if [[ "$ip" =~ ^([0-9]{1,3})\.([0-9]{1,3}|\*)\.([0-9]{1,3}|\*)\.([0-9]{1,3}|\*)$ ]]; then
    for ((i=1;i<=4;i++)); do
      [[ "${BASH_REMATCH[i]}" == '*' || "${BASH_REMATCH[i]}" -le 255 ]] || return 1
    done

    return 0
  fi

  return 1
}

Update according to owner's comment to disallow numbers after “*”:

checkIp()
{
  local ip="$1"
  local asterisk=''

  if [[ "$ip" =~ ^([0-9]{1,3})\.([0-9]{1,3}|\*)\.([0-9]{1,3}|\*)\.([0-9]{1,3}|\*)$ ]]; then
    for ((i=1;i<=4;i++)); do
      [[ "${BASH_REMATCH[i]}" == '*' || ( ! "$asterisk" && "${BASH_REMATCH[i]}" -le 255 ) ]] || return 1
      [[ "${BASH_REMATCH[i]}" == '*' ]] && asterisk='1'
    done

    return 0
  fi

  return 1
}
2

For the record, with zsh, you could write it:

[[ $ip = <0-255>.(<0-255>|"*").(<0-255>|"*").(<0-255>|"*") ]]

Note that it allows 000001.0000255.*.0, but not 0377.1.1.1 (even though 0377 as taken as an octal number is within range), because it only considers decimal numbers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.