While loop com resultado da função - BASH

3

Eu gostaria de comparar o resultado (0 ou 1) de uma função em um loop while. A função validmask verifica se a entrada inserida está no formato de máscara. Se assim for eu recebo 1 , e se não, eu recebo 0 .

Eu quero executar o comando mask=$(whiptail ...) e verificar o valor da função $mask with the validmask 'até que ele retorne uma máscara válida.

Meu problema é que não posso executar a função novamente; meu script sai depois de uma única execução. Eu sei que tenho que colocar a função na instrução if, mas não sei como. Ou há melhor solução?

Aqui está o código:

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

ADICIONADO Função 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
}

Também em loop, enquanto deve ser verificado se a máscara é válida ou não. Eu tenho acima if validmask $mask; then stat2='1'; else stat2='0'; fi codifique o que verifica a entrada vazia.

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

Se eu iniciar meu script, posso preencher apenas uma vez uma máscara. Uma função validmask não é executada novamente.

    
por Michal N. 28.12.2015 / 16:01

3 respostas

2

Basta executar o comando whiptail uma vez e salvar a máscara. Verifique se é válido e, se não, repita até que seja:

## 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
    
por 28.12.2015 / 19:46
3

Seu primeiro problema é:

while validmask
do ...

Nada acontece lá - você chama sua função sem nenhum argumento. E assim, retorna false e o loop pára.

O próximo problema é que você quer executar sua função até que o retorno seja válido. Para fazer isso, você precisa usar until . Eu consegui ignorar isso antes.

Você precisa descartar a primeira instrução if e faça o seguinte:

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

O until loop é a negação booleana do while . Ele será executado até que o comando executado seja verdadeiro.

Também pode ser escrito:

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

Você pode fazer a atribuição / teste de uma só vez:

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

Outro problema é que sua função validmask não é totalmente validada para muitos casos de borda - especialmente aqueles que incluem [*? . Eu acho que você deveria estar usando apenas case e esquecer todas as subdivisões e declarações de variáveis.

Apenas descarte valores inválidos:

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

Uma pequena demonstração:

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

Aqui está outra versão de validmask() que, na minha opinião, valida as máscaras. Eu não percebi antes que as netmasks eram tão restritivas.

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
    
por 28.12.2015 / 18:16
1

Basta mover sua instrução if para o loop while .

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
    
por 28.12.2015 / 16:17

Tags