Sign up ×
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 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.

share|improve this question
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 5 hours ago
    
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 5 hours ago
    
Yes exactly. Until I get valid mask. Plus input won't be empty. – Michal N. 5 hours ago
    
Your validmask() function doesn't validate correctly. – pawel7318 4 hours ago
    
@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. 3 hours ago
up vote 2 down vote accepted

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
share|improve this answer
    
@mikeserv Duh! Thanks, fixed. – terdon 2 hours ago

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
share|improve this answer
1  
Thank you. I fixed it. – Michal N. 2 hours ago

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
share|improve this answer
    
Shoudn't it be while true? – muru 6 hours ago
    
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. 6 hours ago
    
@muru Meanwhile I used your advice I get looped. – Michal N. 5 hours ago
    
My bad, I've fixed the code. – Kira 5 hours ago

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.