Utilisation de l'opérateur non égal pour la comparaison de chaînes

117

J'ai essayé de vérifier si la PHONE_TYPEvariable contient l'une des trois valeurs valides.

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

Le code ci-dessus n'a pas fonctionné pour moi, alors j'ai essayé ceci à la place:

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

Existe-t-il des moyens plus propres pour ce type de tâche?

munish
la source

Réponses:

162

Je suppose que tu cherches:

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

Les règles applicables à ces équivalents sont appelées lois de De Morgan et signifient dans votre cas:

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

Notez le changement d'opérateur booléen ou et et.

Alors que vous avez essayé de faire:

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

Ce qui ne fonctionne évidemment pas.

Nils Werner
la source
28

Un moyen beaucoup plus court serait:

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then 
  echo "Phone type must be nortel, cisco or nec."
fi
  • ^ - Faire correspondre un début en début de ligne
  • $ - Pour faire correspondre la fin de la ligne
  • =~ - L'opérateur de comparaison d'expressions régulières intégré à Bash
0x80
la source
2
Je pense que cela devrait êtreif [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then
Milan Simek
12

De bonnes réponses et une leçon précieuse;) Je veux seulement compléter avec une note.

Le type de test que l'on choisit d'utiliser dépend fortement du code, de la structure, de l'environnement, etc.

Une alternative pourrait être d'utiliser un commutateur ou une caseinstruction comme dans:

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

En deuxième lieu, vous devez faire attention en utilisant des noms de variables en majuscule. Cela permet d'éviter les collisions entre les variables introduites par le système, qui sont presque toujours toutes en majuscules. Ainsi $phone_typeau lieu de $PHONE_TYPE.

Bien que celui-ci soit sans danger, si vous avez pour habitude d'utiliser des majuscules, vous pourriez le dire un jour IFS="boo"et vous serez dans un monde de souffrance.

Cela facilitera également le repérage de ce qui est quoi.

Pas une obligation mais une serait fortement envisager.


C'est probablement aussi un bon candidat pour une fonction. Cela rend le code plus facile à lire et à maintenir. Par exemple:

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
Runium
la source
9

Vous devez utiliser des AND, pas des OR.

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

ou

if [ "$PHONE_TYPE" != "NORTEL" -a "$PHONE_TYPE" != "NEC" -a "$PHONE_TYPE" != "CISCO" ]
then
jlliagre
la source
1

Pour corriger une réponse ci-dessus (car je ne peux pas encore commenter):

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

Veuillez noter que vous avez besoin d’au moins 4 bash pour cette utilisation de = ~
Cela ne fonctionne pas avec bash 3.

J'ai testé sur MS Windows 7 en utilisant bash 4.3.46 (fonctionne bien) et bash 3.1.17 (ne fonctionne pas)

Le LHS de = = doit être entre guillemets. Ci-dessus, PHONE_TYPE = "SPACE TEL" correspondrait également.

Volonté
la source
0

Utilisez [[à la place

if [[ "$PHONE_TYPE" != "NORTEL" ]] || [[ "$PHONE_TYPE" != "NEC" ]] || 
   [[ "$PHONE_TYPE" != "CISCO" ]]
then
echo "Phone type must be nortel,cisco or nec"
exit 1
fi
Swapnil
la source
2
Ceci est, bien sûr, faux. [[vs [n'aide pas avec la logique étant hors tension.
ilkkachu
0

Juste une proposition de variante basée sur la solution @ 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
tdaget
la source