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


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.


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


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"; }

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"

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.