Il s'agit d'un cas d'angle très obscur que l'on pourrait considérer comme un bug dans la façon dont le test [
intégré est défini; cependant, il correspond au comportement du [
binaire réel disponible sur de nombreux systèmes. Pour autant que je peux dire, il ne touche que certains cas et une variable ayant une valeur qui correspond à un [
opérateur comme (
, !
, =
, -e
et ainsi de suite.
Permettez-moi d'expliquer pourquoi et comment contourner ce problème dans les shells Bash et POSIX.
Explication:
Considérer ce qui suit:
x="("
[ "$x" = "(" ] && echo yes || echo no
Aucun problème; ce qui précède ne produit aucune erreur et produit yes
. C'est ainsi que nous nous attendons à ce que les choses fonctionnent. Vous pouvez changer la chaîne de comparaison '1'
si vous le souhaitez, et la valeur de x
, et cela fonctionnera comme prévu.
Notez que le /usr/bin/[
binaire réel se comporte de la même manière. Si vous exécutez, par exemple, '/usr/bin/[' '(' = '(' ']'
il n'y a pas d'erreur, car le programme peut détecter que les arguments consistent en une opération de comparaison de chaîne unique.
Le bogue se produit lorsque nous et avec une deuxième expression. Peu importe la deuxième expression, tant qu'elle est valide. Par exemple,
[ '1' = '1' ] && echo yes || echo no
sorties yes
, et est évidemment une expression valide; mais, si nous combinons les deux,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Bash rejette l'expression si et seulement si x
est (
ou !
.
Si nous devions exécuter ce qui précède en utilisant le [
programme réel , à savoir
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
l'erreur serait compréhensible: puisque le shell effectue les substitutions de variables, le /usr/bin/[
binaire ne reçoit que les paramètres (
=
(
-a
1
=
1
et la terminaison ]
, il échoue naturellement à analyser si les parenthèses ouvertes commencent ou non une sous-expression, une opération et une opération étant impliquées. Bien sûr, l'analyser comme deux comparaisons de chaînes est possible, mais le faire avec avidité comme cela pourrait causer des problèmes lorsqu'il est appliqué à des expressions appropriées avec des sous-expressions entre parenthèses.
Le problème, en fait, est que le shell [
intégré se comporte de la même manière, comme s'il développait la valeur de x
avant d'examiner l'expression.
(Ces ambiguïtés, et d'autres liées à l'expansion des variables, étaient une grande raison pour laquelle Bash a implémenté et recommande désormais d'utiliser les [[ ... ]]
expressions de test à la place.)
La solution de contournement est triviale et souvent vue dans les scripts utilisant des sh
shells plus anciens . Vous ajoutez souvent un caractère "sûr" x
devant les chaînes (les deux valeurs étant comparées), pour vous assurer que l'expression est reconnue comme une comparaison de chaînes:
[ "x$x" = "x(" -a "x$y" = "x1" ]
[[ "$x" = '1' && "$y" = '1' ]]