web-dev-qa-db-ja.com

関数の結果を含むwhileループ-BASH

Whileループ内の関数の結果(0または1)を比較したいと思います。関数validmaskは、入力された入力がマスク形式であるかどうかをチェックします。もしそうなら私は_1_を取得し、そうでなければ私は_0_を取得します。

mask=$(whiptail ...)コマンドを実行し、有効なマスクが返されるまで_$mask with the_ validmask`関数の値を確認したいと思います。

私の問題は、関数を再度実行できないことです。スクリプトは1回実行すると終了します。関数をifステートメントに入れる必要があることは知っていますが、その方法がわかりません。またはより良い解決策はありますか?

これがコードです:

_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
_

[〜#〜]追加[〜#〜]関数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
}
_

また、ループ中は、マスクが有効かどうかを確認する必要があります。空の入力をチェックする上記 _if validmask $mask; then stat2='1'; else stat2='0'; fi_コードを取得しました。

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

スクリプトを開始すると、マスクを1回だけ入力できます。関数validmaskは再度実行されません。

3
Michal N.

whiptailコマンドを1回実行して、マスクを保存するだけです。有効かどうかを確認し、有効でない場合は、次のようになるまで繰り返します。

## 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
2
terdon

あなたの最初の問題は:

_while validmask
do ...
_

そこでは何も起こりません-引数なしで関数を呼び出します。そして、それはfalseを返し、ループが停止します。

次の問題は、関数を実行することですntil戻り値は有効です。そのためには、untilを使用する必要があります。私は以前これをなんとか見落としていました。

最初のifステートメントを削除して、次の操作を行う必要があります。

_until validmask "$mask"
do    mask=$(get_new_value)
done
_

untilループは、whileのブール否定です。実行するコマンドがtrueを返すまで実行されます。

それはまた書くことができます:

_while ! validmask "$mask"
do    mask=$(get_new_mask)
done
_

あなたはすぐに割り当て/テストを行うかもしれません:

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

もう1つの問題は、validmask関数が、多くのEdgeケース(特に_[*?_を含むケース)に対して完全に検証できないことです。 caseを使用するだけで、補助的な分割と変数の宣言をすべて気にしないでください。

悪い値を除外するだけです:

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

小さなデモ:

_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
_

これはvalidmask()の別のバージョンで、私が思うに、実際にマスクを検証します。ネットマスクがそれほど制限的であることを私は前に知りませんでした。

_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
_
3
mikeserv

ifステートメントを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
1
Kira