文字列の比較に等しくない演算子を使用する


117

PHONE_TYPE変数に3つの有効な値のいずれかが含まれているかどうかを確認しようとしました。

if [ "$PHONE_TYPE" != "NORTEL" ] || [ "$PHONE_TYPE" != "NEC" ] ||
   [ "$PHONE_TYPE" != "CISCO" ]
then
    echo "Phone type must be nortel,cisco or nec"
    exit
fi

上記のコードは私にはうまくいきませんでしたので、代わりにこれを試しました:

if [ "$PHONE_TYPE" == "NORTEL" ] || [ "$PHONE_TYPE" == "NEC" ] ||
   [ "$PHONE_TYPE" == "CISCO" ]
then
    :        # do nothing
else
    echo "Phone type must be nortel,cisco or nec"
    exit
fi

このタイプのタスクのためのよりクリーンな方法はありますか?

回答:


162

あなたが探していると思います:

if [ "$PHONE_TYPE" != "NORTEL" ] && [ "$PHONE_TYPE" != "NEC" ] &&
   [ "$PHONE_TYPE" != "CISCO" ]

これらの同等物の規則は、デモーガンの法則と呼ばれ、あなたの場合は以下を意味します。

not(A || B || C) => not(A) && not(B) && not (C)

ブール演算子orおよびandの変更に注意してください。

あなたがしようとしたのに対し:

not(A || B || C) => not(A) || not(B) || not(C)

これは明らかに機能しません。


28

はるかに短い方法は次のとおりです。

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then 
  echo "Phone type must be nortel, cisco or nec."
fi
  • ^ –行の先頭から一致する
  • $ –行末に合わせる
  • =~ -Bashの組み込み正規表現比較演算子

2
私はそれがあるべきだと思うif [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then
ミラノSimek

12

良い答え、そして貴重なレッスン;)メモだけで補足したい。

使用するテストの種類は、コード、構造、環境などに大きく依存します。

別の方法は、次のようにスイッチまたはcaseステートメントを使用することです。

case "$PHONE_TYPE" in
"NORTEL"|"NEC"|"CISCO")
    echo "OK"
    ;;
*)
    echo "Phone type must be nortel,cisco or nec"
    ;;
esac

2番目の注意として、大文字の変数名を使用することに注意する必要があります。これは、システムによって導入される変数間の衝突を防ぐためです。ほとんどの場合、これはすべて大文字です。したがって、の$phone_type代わりに$PHONE_TYPE

それは安全ですが、すべて大文字を使用する習慣がある場合、いつか言うかもしれずIFS="boo"、あなたは怪我の世界にいます。

また、どちらが何であるかを見つけやすくなります。

する必要はありませんが、強く検討します。


また、おそらく関数の良い候補です。これにより、コードの読み取りと保守が簡単になります。例えば:

valid_phone_type()
{
    case "$1" in
    "NORTEL"|"NEC")
        return 0;;
    *)
        echo "Model $1 is not supported"
        return 1;;
    esac
}

if ! valid_phone_type "$phone_type"; then
    echo "Bye."
    exit 1
fi

9

ORではなくANDを使用する必要があります。

if [ "$PHONE_TYPE" != "NORTEL" ] && [ "$PHONE_TYPE" != "NEC" ] && [ "$PHONE_TYPE" != "CISCO" ]
then

または

if [ "$PHONE_TYPE" != "NORTEL" -a "$PHONE_TYPE" != "NEC" -a "$PHONE_TYPE" != "CISCO" ]
then

1

上記の回答を修正するには(まだコメントできないため):

PHONE_TYPE="NORTEL"
if [[ $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO|SPACE TEL)$ ]]; then 
  echo "Phone type accepted."
else
  echo "Error! Phone type must be NORTEL, CISCO or NEC."
fi

=〜のこの使用には少なくともbash 4が必要であることに注意してください。bash3
では機能しません。

bash 4.3.46(正常に動作します)とbash 3.1.17(動作しませんでした)を使用してMS Windows 7でテストしました

=〜のLHSは引用符で囲む必要があります。上記では、PHONE_TYPE = "SPACE TEL"も一致します。


0

代わりに[[

if [[ "$PHONE_TYPE" != "NORTEL" ]] || [[ "$PHONE_TYPE" != "NEC" ]] || 
   [[ "$PHONE_TYPE" != "CISCO" ]]
then
echo "Phone type must be nortel,cisco or nec"
exit 1
fi

2
もちろん、これは間違っています。[[vs [は、ロジックがオフになっていると役に立ちません。
イルカチュウ

0

@ 0x80ソリューションに基づいたバリエーション提案:

# define phone brand list
phoneBrandList=" NORTEL NEC CISCO" ## separator is space with an extra space in first place

# test if user given phone is contained in the list
if [[ ${phoneBrandList} =~ (^|[[:space:]])"${userPhoneBrand}"($|[[:space:]]) ]]; then
    echo "found it !"
fi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.