3

I would like to compare the result (0 or 1) of a function in a while loop. Function validmask checks whether the entered input is in mask format. If so I get 1, and if not I get 0.

I want to run the mask=$(whiptail ...) command and check the value of $mask with thevalidmask` function until it returns a valid mask.

My problem is that I can't run the function again; my script exits after a single run. I know I have to put the function in the if statement, but I don't know how. Or is there better solution?

Here is the code:

if validmask $mask; then stat2='1'; else stat2='0'; fi
while validmask
do
   if [[ $stat2 == 0 ]]; then
        mask=$(whiptail --title "xx" --inputbox --nocancel "Bad entry" 3>&1 1>&2 2>&3)
   fi
done

ADDED Function validmask

function validmask()
{
    local  mask=$1
    local  stat2=1

    if [[ $mask =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        OIFS=$IFS
        IFS='.'
        mask=($mask)
        IFS=$OIFS
        [[ ${mask[0]} -le 255 && ${mask[1]} -le 255 \
            && ${mask[2]} -le 255 && ${mask[3]} -le 255 ]]
        stat2=$?
    fi
    return $stat2
}

Also in loop while should be check if mask is valid or not. I got above if validmask $mask; then stat2='1'; else stat2='0'; fi code what checks empty input.

while [[ -z "$mask" ]]
do
   mask=$(whiptail --title "xx" --inputbox --nocancel "Mask" 3>&1 1>&2 2>&3)
done

If I start my script I am able to fill in just one time a mask. A function validmask is not executed again.

terdon
  • 234,489
  • 66
  • 447
  • 667
Michal N.
  • 121
  • 1
  • 3
  • 11
  • 1
    Please [edit] your question and show us the entire script. Where is `validmask` defined? How does it work? What is it doing in the while loop? – terdon Dec 28 '15 at 15:33
  • Thanks for the edit. It's still not very clear though. What exactly are you looping for? Do you want to repeat the `whiptail` command until you get a valid mask? Do you want to repeat it for ever? – terdon Dec 28 '15 at 15:51
  • Yes exactly. Until I get valid mask. Plus input won't be empty. – Michal N. Dec 28 '15 at 15:56
  • Your `validmask()` function doesn't validate correctly. – pawel7318 Dec 28 '15 at 17:28
  • @pawel7318 what do you mean not correctly? It returns 1 if mask is valid (e.g. 255.255.255.0), returns 0 (2555555.555.552.99) – Michal N. Dec 28 '15 at 17:53
  • How about 100.0.0.0 or 255.0.255.0 ? – pawel7318 Dec 28 '15 at 18:14
  • @pawel7318 - are those invalid? – mikeserv Dec 28 '15 at 20:02
  • @mikeserv - if we're talking about netmask (I assume we do) than yes, those are invalid. – pawel7318 Dec 28 '15 at 21:31
  • @pawel7318 - the only valid netmasks are `(255.)*((2(24|4[08]|5[0245])|1(92|28)|0).)` is that right? And the value must always descend, and there can be never be more than a single octet which is not either 255 or 0, right? – mikeserv Dec 28 '15 at 23:08

3 Answers3

3

Your first problem is:

while validmask
do ...

Nothing ever happens there - you call your function without any arguments. And so it returns false and the loop stops.

The next problem is you want to run your function until the return is valid. To do that, you need to use until. I managed to overlook this before.

You need to drop the first if statement and just do:

until validmask "$mask"
do    mask=$(get_new_value)
done

The until loop is the boolean negation of the while. It will run until the command it runs returns true.

It can also be written:

while ! validmask "$mask"
do    mask=$(get_new_mask)
done

You might do the assignment / test at once:

unset mask
until validmask "${mask:=$(get_new_value)}"
do    mask=
done

Another problem is that your validmask function fails to fully validate for a lot of edge cases - especially those which include [*?. I think you should just be using case and nevermind all of the ancillary splitting and variable declarations.

Just rule out bad values:

validmask()
    case    "${1##*[!0-9.]*}"       in
    (.*|*.|*..*|*.*.*.*.*|*[!.][!.][!.][!.]*) ! :;;
    (*[3-9][!.][!.]*|*2[6-9][!.]*|*25[6-9]*)  ! :;;
    (*.*.*.*)       ;;              (*)       ! :;;
    esac

A little demo:

for mask in              \
         0.0.0.0         \
         0.0.0.          \
         0.0.0.1233      \
         0.0.0.233       \
         0.0..233        \
         0.0.2.233       \
         0.5555.2.233    \
         0.55.2.233      \
         .55.2.233       \
         1.55.2.233      \
         255.255.255.255 \
         255.255.256.255
do    validmask "$mask"
      printf "%-16.16s: %.$?0s%.$((!$?*4))s\n%.d" \
             "$mask" bad good  "0$(($?*8))"
      printf "printf's return:\t $?\n\n"
done  2>/dev/null

0.0.0.0         : good
printf's return:     0

0.0.0.          : bad
printf's return:     1

0.0.0.1233      : bad
printf's return:     1

0.0.0.233       : good
printf's return:     0

0.0..233        : bad
printf's return:     1

0.0.2.233       : good
printf's return:     0

0.5555.2.233    : bad
printf's return:     1

0.55.2.233      : good
printf's return:     0

.55.2.233       : bad
printf's return:     1

1.55.2.233      : good
printf's return:     0

255.255.255.255 : good
printf's return:     0

255.255.256.255 : bad
printf's return:     1

Here's another version of validmask() which, as I think, actually validates the masks. I didn't realize before that the netmasks were so restrictive.

validmask()
    case    ."${1##*[!.0124589]*}".      in
    (*.*.*.*.*.*.*|*[!.][!.][!.][!.]*) ! :;;
    (*[!.25]*.[!0]*|*.[!012]*|*0[!.]*) ! :;;
    (*1[!29]*|*1?[!28]*|*98*|*.2?.*)   ! :;;
    (*4[!.08]*|*[.2][25][!245]*)       ! :;;
    (.*.*.*.*.)  echo "$1";; (*)       ! :;;
    esac

a=-1 b=0 c=0 d=0
for o in a b c d
do    while  [ "$(($o+=1))" -lt 1000 ] ||
             ! : "$(($o=255))"
      do     validmask "$a.$b.$c.$d"
done; done

0.0.0.0
128.0.0.0
192.0.0.0
224.0.0.0
240.0.0.0
248.0.0.0
252.0.0.0
254.0.0.0
255.0.0.0
255.128.0.0
255.192.0.0
255.224.0.0
255.240.0.0
255.248.0.0
255.252.0.0
255.254.0.0
255.255.0.0
255.255.128.0
255.255.192.0
255.255.224.0
255.255.240.0
255.255.248.0
255.255.252.0
255.255.254.0
255.255.255.0
255.255.255.128
255.255.255.192
255.255.255.224
255.255.255.240
255.255.255.248
255.255.255.252
255.255.255.254
255.255.255.255
mikeserv
  • 57,448
  • 9
  • 113
  • 229
2

Just run the whiptail command once and save the mask. Check if it is valid and, if not, repeat until it is:

## Get the 1st mask
mask=$(whiptail --title "xx" --inputbox --nocancel "Bad entry" 3>&1 1>&2 2>&3)
## If it isn't valid, repeat until it is
until validmask "$mask"; do
    mask=$(whiptail --title "xx" --inputbox --nocancel "Bad entry" 3>&1 1>&2 2>&3)
done
terdon
  • 234,489
  • 66
  • 447
  • 667
1

Just move your if statement to your while loop.

while true
do
   if ! validmask $mask; then
        mask=$(whiptail --title "xx" --inputbox --nocancel "Bad entry" 3>&1 1>&2 2>&3)
   else
       break
   fi
done
Kira
  • 4,727
  • 3
  • 17
  • 33