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
   if [[ $stat2 == 0 ]]; then
        mask=$(whiptail --title "xx" --inputbox --nocancel "Bad entry" 3>&1 1>&2 2>&3)

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
        [[ ${mask[0]} -le 255 && ${mask[1]} -le 255 \
            && ${mask[2]} -le 255 && ${mask[3]} -le 255 ]]
    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" ]]
   mask=$(whiptail --title "xx" --inputbox --nocancel "Mask" 3>&1 1>&2 2>&3)

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

  • 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., returns 0 (2555555.555.552.99) – Michal N. Dec 28 '15 at 17:53

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)
| improve this answer | |

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)

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)

You might do the assignment / test at once:

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

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:

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

A little demo:

for mask in              \         \
         0.0.0.          \      \       \
         0.0..233        \       \
         0.5555.2.233    \      \
         .55.2.233       \      \ \
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         : good
printf's return:     0

0.0.0.          : bad
printf's return:     1      : bad
printf's return:     1       : good
printf's return:     0

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

0.5555.2.233    : bad
printf's return:     1      : good
printf's return:     0

.55.2.233       : bad
printf's return:     1      : good
printf's return:     0 : good
printf's return:     0 : 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.

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

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
| improve this answer | |

Just move your if statement to your while loop.

while true
   if ! validmask $mask; then
        mask=$(whiptail --title "xx" --inputbox --nocancel "Bad entry" 3>&1 1>&2 2>&3)
| improve this answer | |
  • Shoudn't it be while true? – muru Dec 28 '15 at 15:28
  • I used your code but I got an error "command not found" I guess I got wrong function. I am enclosing a screen of code function. [link]postimg.org/image/jmkr7a8mb – Michal N. Dec 28 '15 at 15:30
  • @muru Meanwhile I used your advice I get looped. – Michal N. Dec 28 '15 at 15:31
  • My bad, I've fixed the code. – Kira Dec 28 '15 at 15:34

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.