Alexis Cimpu
Alexis Cimpu

Reputation: 321

Wildcard bash not working

I'm trying to make a case statement and i am using the following wildcards to make the diff between the arguments:

This is for a single IP:

case $1 in
//the argument is a single IP    
*.*.*.0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31`|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|126|127|128|129|130|131|132|133|134|135|136|137|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|158|159|160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189|190|191|192|193|194|195|196|197|198|199|200|201|202|203|204|205|206|207|208|209|210|211|212|213|214|215|216|217|218|219|220|221|222|223|224|225|226|227|228|229|230|231|232|233|234|235|236|237|238|239|240|241|242|243|244|245|246|247|248|249|250|251|252|253|254|255 )

        ....`
//the argument is a IP range

    `*.*.*.*-*.*.*.* )

    ....`

Even so, it seems that its not working, what am I doing wrong?

thanks,

Upvotes: 0

Views: 379

Answers (2)

gniourf_gniourf
gniourf_gniourf

Reputation: 46813

Maybe this little loop can help you:

#!/bin/bash

shopt -s extglob

is_a_byte() {
    local i
    for i do
       [[ "$i" = +([[:digit:]]) ]] && ((10#$i<=255)) || return 1 
    done
}

is_ip() {
    local ipn
    read -a ipn <<< "${1//./ }"
    if [[ "${#ipn[@]}" = 4 ]] && is_a_byte "${ipn[@]}"; then
       [[ "$2" ]] && printf -v "$2" "%s" $(( ((((((10#${ipn[0]}<<8)|10#${ipn[1]})<<8)|10#${ipn[2]})<<8)|10#${ipn[3]}) ))
       return 0
    else
       return 1
    fi
}

while IFS=- read -e -r -p "Enter an IP or an IP range: " -a ip; do
   if [[ -z ${ip[1]} ]]; then
      if is_ip "${ip[0]}" N; then
         echo "Valid IP ---> $N"
      else
         echo "${ip[0]} is not a valid IP"
      fi
   else
      if is_ip "${ip[0]}" N[0] && is_ip "${ip[1]}" N[1]; then
         ((N[0]>N[1])) && N=( "${N[1]}" "${N[0]}" )
         echo "Valid IP range ---> ${N[0]}-${N[1]}"
      else
         echo "${ip[0]}-${ip[1]} is not a valid IP range"
      fi
   fi
done

No grep, no subshell, only pure bash, and it is much more robust than a clumsy glob/regex, and I would say it's rather elegant ;-).

Upvotes: 1

Olaf Dietsche
Olaf Dietsche

Reputation: 74018

For the single IP, you have defined these alternatives

  • *.*.*.0
  • 1
  • 2
  • ...

and not

  • *.*.*.0
  • *.*.*.1
  • *.*.*.2
  • ...

The pattern type used here is called glob.

If you really want to spell it out, you have to say

*.*.*.0|*.*.*.1|*.*.*.2|...)

When you want to have at most three characters, you can specify this as well

*.*.*.?|*.*.*.??|*.*.*.???)

or with at most three digits

*.*.*.[0-9]|*.*.*.[0-9][0-9]|*.*.*.[0-9][0-9][0-9])

but this allows e.g. 127.1.3.843 as well.

If you have

case "$arg" in
single-IP) ... ;;
IP-range) ... ;;
esac

it will first test single-IP, which always matches. To match ranges as well, you must list the pattern for the IP range first

case "$arg" in
IP-range) ... ;;
single-IP) ... ;;
esac

then it tests the IP range case first, and only if it doesn't match tests for the single IP pattern.

For a simplified test, see

case "$1" in
*.*.*.*-*.*.*.*) echo range ;;
*.*.*.*) echo single ;;
*) echo else ;;
esac

this gives

$ sh /tmp/a.sh 1.2.3.4
single
$ sh /tmp/a.sh 1.2.3.4-5.6.7.8
range
$ sh /tmp/a.sh 1.2.3
else

Upvotes: 4

Related Questions