Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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.

share|improve this question
    
Detect the * and dynamically change it or evaluate it as 255? –  Christopher Jan 30 '13 at 14:05
    
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). –  Stephane Chazelas Jan 30 '13 at 15:27
add comment

2 Answers

up vote 3 down vote accepted

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
}
share|improve this answer
    
Was very useful, thanks so much. –  X3MBoy Jan 30 '13 at 14:36
add comment

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.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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