Tout d'abord, il n'est pas nécessaire de mettre les noms de variables en majuscules. En général, les noms de variables en majuscules doivent être réservés à ceux qui sont utilisés dans le cadre d'un projet. export
dans l'environnement au profit d'autres exécutables.
Deuxièmement, ce que vous avez avec &&
devrait fonctionner, mais elle n'est pas très résistante face à une variable d'état qui peut être vide ou non numérique.
Enfin, le -a
n'a pas fonctionné car -a
fait partie de la syntaxe de test
/ [
... ]
; c'est parti à l'intérieur les crochets.
Fondamentalement, la chose la plus importante à savoir sur les conditionnelles dans le shell est que ce ne sont que des ordres . Cette expression si :
if foo; then
echo true
else
echo false
fi
Fait exactement la même chose que celui-ci :
foo
if [ $? -eq 0 ]; then
echo true
else
echo false
fi
Ainsi, après le if
(ou while
ou until
) peut être n'importe quelle commande.
Il en va de même pour le &&
y ||
les opérateurs aussi : les éléments situés de part et d'autre ne sont que des commandes. La séquence foo && bar
exécute la commande foo
et ensuite, seulement si cette commande s'est terminée avec le statut 0, il exécute bar
. (Il s'agit donc en fait d'une abréviation de if foo; then bar; fi
.) De même, foo || bar
courses foo
puis, si cette commande se termine par non nul statut, exécutions bar
. (Il s'agit donc en fait d'une abréviation de if ! foo; then bar; fi
.)
C'est la principale chose qui échappe à de nombreux programmeurs débutants. L'interpréteur de commandes n'a pas d'expressions en soi, juste des commandes à exécuter.
Cependant, comme vous souhaitez souvent effectuer des comparaisons et d'autres opérations qui seraient des expressions booléennes dans les langages de programmation classiques non shell, il existe une commande spéciale que vous pouvez lancer pour les effectuer. Il s'agissait autrefois d'une commande binaire distincte, mais elle est aujourd'hui intégrée à l'interpréteur de commandes. Son vrai nom est test
mais il peut également être invoqué sous la forme [
Dans ce cas, il se plaindra si son dernier argument n'est pas un ]
. Les arguments à l'intérieur des crochets ou après test
constitue une expression à évaluer, et la commande test sort avec le statut 0 si l'expression est vraie, et non nul si elle est fausse. Il s'agit donc du genre de chose qui est normalement ce qu'un if
attend dans d'autres langages de programmation en une commande que vous pouvez exécuter, la traduisant ainsi pour l'interpréteur de commandes.
L'apparition de [
... ]
peut être trompeur ; il est en fait analysé comme s'il s'agissait de l'orthographe test
avec le même traitement en ligne de commande que n'importe quelle commande du shell. Cela signifie que si vous essayez de comparer des choses en utilisant <
ou >
ils seront interprétés comme des redirections. Essayez d'utiliser (
y )
pour le regroupement et vous créerez un sous-shell (et générerez probablement une erreur de syntaxe en le faisant au milieu des arguments d'une commande). Essayez de combiner des expressions avec &&
y ||
à l'intérieur des crochets et vous terminerez la commande prématurément, ce qui entraînera à nouveau une erreur de syntaxe.
Vous pouvez toujours utiliser &&
y ||
fuera de des crochets ; à ce stade, vous exécutez simplement plusieurs instances de la commande de test au lieu d'une seule. Mais vous pouvez également utiliser -a
y -o
tant qu'ils sont à l'intérieur les crochets. Ces deux pipelines produisent donc le même résultat :
[ "$status" -ne 200 -a "$string" != "$value" ]
[ "$status" -ne 200 ] && [ "$string" != "value" ]
La différence est que la première est vérifiée par une instance de la fonction test
tandis que le second en exécute deux.
Le shell Korn a introduit une nouvelle version de la commande test qui s'écrit avec deux crochets au lieu d'un, entre lesquels se trouve un environnement syntaxique spécial qui n'est pas analysé de la même manière qu'une commande normale. Entre les doubles crochets, vous pouvez utiliser en toute sécurité des expansions de paramètres non citées, des parenthèses non citées pour le regroupement, <
y >
pour la comparaison de chaînes de caractères (s'en tenir à -lt
y -gt
pour une comparaison numérique), et &&
y ||
en tant qu'opérateurs booléens. [[
... ]]
ajoute également la possibilité de faire correspondre des motifs globaux ( [[
foo == f* ]]
) et les expressions régulières ( [[ foo =~ ^f ]]
).
Les shells modernes tels que Bash et Zsh ont hérité de cette construction de Ksh, mais elle ne fait pas partie de la spécification POSIX. Si vous êtes dans un environnement où vous devez être strictement conforme à POSIX, ne l'utilisez pas ; sinon, c'est une question de préférence personnelle.
Notez que l'expression de substitution arithmétique $((
... ))
es fait partie de POSIX, et ses règles sont très similaires à celles de la norme [[
... ]]
. La principale différence est que les tests d'égalité et d'inégalité (qui produisent ici une valeur numérique, 0 pour faux et 1 pour vrai) sont effectués numériquement au lieu d'être effectués par chaîne de caractères : [[ 10 < 2 ]]
est vrai, mais $(( 10 < 2 ))
produit 0.
Là encore, les shells modernes se sont appuyés sur la spécification POSIX pour ajouter une fonction indépendante $
-Version allégée de ((
... ))
qui fonctionne comme une citation automatique let
que vous pouvez utiliser dans if
expressions si vous avez affaire à des chiffres. Ainsi, votre première condition pourrait également s'écrire (( status != 200 ))
. Encore une fois, en dehors de l'obligation de s'en tenir à POSIX, c'est une question de préférence personnelle. J'aime utiliser ((
... ))
chaque fois que j'ai affaire à des chiffres, mais d'autres préfèrent s'en tenir à [
ou [[
et utiliser les opérateurs numériques comme -lt
.
Pour ce que cela vaut, voici comment je réécrirais votre code :
website=domain.com
subject="$website DOWN!"
email=an@email.com
value="string_to_search"
status=$(curl -sI "$website" | awk '/HTTP\/1.1/ { print $2 }')
string=$(curl -s "$website" | grep -o "$value")
if (( status != 200 )) && [[ $string != $value ]]; then
mail -s "$subject" "$email" <<<"Website: $website is down, status code: '$status' - $(date)"
fi