Comparez efficacement si la variable existe et n'est pas égale

3

J'ai un problème avec la shsyntaxe du script. J'ai écrit un script pour mon routeur Asus. Le script fonctionne parfaitement. Mais j'ai cette ligne:

if [[ "$OldIP" && "$StartIP" != "$OldIP" ]]; then echo OK; fi

Cela ne devrait être vrai (et exécuter echo OK) que si $StartIPet $OldIPne sont pas identiques. La ligne fonctionne, mais j'aimerais que cela se fasse plus efficacement. Les variables contiennent des adresses IP valides.

Dans certains cas, $OldIPrien ne sera attribué (n'est pas initialisé). Mais, si $OldIPn'existe pas, cela signifie qu'ils ne sont pas les mêmes dans ma coquille!

Je ne veux pas que la ligne à faire: si $OldIPn'existe pas -> tester si elles sont différentes -> exécuter echo OK.

Je veux que la ligne signifie: a) si $OldIPn'existe pas -> fin. plus b) s'il $OldIPexiste -> teste si elles sont différentes -> exécutez echo OK.

Donc, je voudrais supprimer en "$OLDIP" &&quelque sorte, si possible. Pas un vrai problème curieux d'apprendre :)

En quelque sorte (mais ça ne marche pas):

if [ [ "$OldIP" ] != "$StartIP" ]; then echo OK; fi

ou

if [ $OldIP != "$StartIP" ]; then echo OK; fi

qui fait ce que je veux, mais se plaint quand OldIP est vide (mais fonctionne bien)

tandis que

if [ "$OldIP" != "$StartIP" ]; then echo OK; fi

fonctionne mais ignore que OldIP est vide

Pila
la source
Vous avez deux conditions à vérifier, vous devez les avoir toutes les deux de manière logique. Cependant, de nombreuses langues (y compris tous les scripts de shell que je connais) vont "court-circuiter" les opérateurs logiques. Si "$ OLDIP" est évalué à false, le reste de l'expression ne sera pas évalué puisqu'il ne modifiera pas la logique à tester.
user1794469
Cela ressemble à une optimisation prématurée. Avez-vous profilé le script pour vous assurer que c'est vraiment le goulot d'étranglement?
Raphael Ahrens
Problème purement de curiosité. J'aimerais que l'instruction soit: if [["$ OldIP"! = "$ StartIP"]]; alors echo OK; fi mais il ignore l'état non existant d'OldtIP
Pila

Réponses:

2

Strictement parlant, une variable n’existe pas si elle n’a jamais été affectée à une valeur ou si elle l’a été unset. Une variable avec une chaîne vide comme valeur existe .

Le paramètre de développement standard ${variable+value}remplacera la chaîne valuelorsqu'elle variableexiste (n'est pas non définie ou vide). Cela pourrait être utilisé pour tester l'existence comme ceci:

if [ "${OldIP+x}" = "x" ] && [ "$OldIP" != "$StartIP" ]; then
    # code
fi

Pour tester si OldIPexiste dans bash, utilisez le -vtest:

 if [[ -v OldIP ]] && [[ "$OldIP" != "$StartIP" ]]; then
     # code
 fi

Ceci effectuerait la comparaison de chaîne entre $OldIPet $StartIPseulement si OldIPavait déjà été défini (même s'il était défini sur une chaîne vide). Notez que le -vtest prend le nom de la variable.

Kusalananda
la source
busyboxsh ne supporte pas -v. Vous pouvez utiliser [ "${OldIP+set}" = set ]là-bas.
Stéphane Chazelas
@ StéphaneChazelas Désolé, je ne lis pas les balises et je suppose que c'était pour bash. Ma faute. Merci pour la suggestion.
Kusalananda
0

Je pense que votre script est assez efficace tel quel. Vous ne passez certainement pas beaucoup de cycles à ce sujet.

Une autre façon d'écrire la logique:

{ test -n "$OldIP" || test "$StartIP" != "$OldIP"; } && echo OK

Ceci dit "si OldIP est défini ou si OldIP et StartIP sont différents, alors echo OK.

N'oubliez pas que [c'est un autre nom pour test(1)lequel vous pouvez lire man 1 test.

Edit: Comme Gilles l’a fait remarquer, veillez à ne pas créer de sous-shell ( ... )où ils ne sont pas nécessaires.

{ ... ; } peut être utilisé pour regrouper des commandes sans exécuter un nouveau shell.

Brève référence: http://www.gnu.org/software/bash/manual/html_node/Command-Grouping.html

ssh2ksh
la source
1
La création d'un sous-shell réduit les performances. { test … || test …; } && echo OKferait la même chose sans créer un sous-shell. Ce ne serait pas une nette amélioration des performances par rapport à l'original (peut-être une légère différence d'une manière ou d'une autre selon le shell0.)
Gilles
Merci Gilles, comme il serait ironique de ralentir le processus! J'ai mis à jour ma réponse pour refléter votre indice.
ssh2ksh
0

Cela fait ce que vous demandez:

[ "${OldIP:-"$StartIP"}" != "$StartIP" ] && echo "OK"

Comme aussi ceci (plus complexe):

${OldIP:+false} || { [[ $OldIP != $StartIP ]] && echo "OK"; }

la source
0

Si vous utilisez bash, vous pouvez utiliser une substitution par défaut:

[[ "${OldIP:=oldunset}" != "${StartIP?StartUnset" ]] && echo "OK"

La syntaxe ${var:-def}sera évaluée à la valeur actuelle de $varou à la valeur par défaut spécifiée (dans ce cas, def) si la variable est non définie ou nulle. La valeur de la variable (s'il y en a une) est inchangée.

La syntaxe se ${var?message}terminera avec un code d'erreur de 1 avec un message de messageif $varnon défini ou nul.

Si vous avez explicitement besoin de testtests compatibles, vous pouvez le faire:

[ ! -z "$OldIP" -a "$OldIP" != "$StartIP" ] && echo "OK"
DopeGhoti
la source
2
! -z "STRING"est identique -n "STRING" (ou juste "STRING")
cas
Votre proposition avec ${OldIP:=unset}échoue la valeur de StartIPest unset. Si ce sont des adresses IP comme le nom l'indique, cela ne se produira pas, mais le code sera fragile: que se passera-t-il si le script prend en charge les noms d'hôte un jour?
Gilles
Facilement réparé. Je le ferai tout de suite.
DopeGhoti