web-dev-qa-db-fra.com

Utilisation de l'opérateur différent pour la comparaison de chaînes

J'ai essayé de vérifier si le PHONE_TYPE la variable 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 ne fonctionnait pas pour moi, j'ai donc 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?

134
munish

Je suppose que vous cherchez:

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

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

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

Notez la modification de l'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.

193
Nils Werner

Un moyen beaucoup plus court serait:

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|Cisco)$ ]]; then 
  echo "Phone type must be nortel, Cisco or nec."
fi
  • ^ - Pour faire correspondre un début au début de la ligne
  • $ - Pour correspondre à la fin de la ligne
  • =~ - Opérateur de comparaison d'expressions régulières intégré à Bash
38
0x80

Bonnes réponses, et une leçon inestimable;) 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 instruction case comme dans:

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

Comme deuxième note, vous devez être prudent en utilisant des noms de variables en majuscules. Il s'agit d'éviter la collision entre les variables introduites par le système, qui est presque toujours entièrement en majuscules. Donc $phone_type au lieu de $PHONE_TYPE.

Bien que celui-ci soit sûr, si vous avez l'habitude d'utiliser tous les majuscules, un jour vous pourriez dire IFS="boo" et vous êtes dans un monde de souffrance.

Il sera également plus facile de repérer ce qui est quoi.

Pas un devoir mais un considérerait fortement.


C'est aussi probablement un bon candidat pour une fonction. Cela facilite la lecture et la maintenance du code. 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
13
Runium

Vous devez utiliser des ET et non des OU.

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
11
jlliagre

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 bash 4 pour cette utilisation de = ~
Cela ne fonctionne pas dans bash 3.

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

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

2
Will

Juste une proposition de variation 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
0
tdaget

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
0
Swapnil