web-dev-qa-db-fra.com

Opérateurs logiques multiples, ((A || B) && C) et "erreur de syntaxe près d'un jeton inattendu"

Je travaille avec Bash 3 et j'essaye de former un conditionnel. En C/C++, son simple mort: ((A || B) && C). Dans Bash, cela ne s'est pas avéré (je pense que les auteurs Git ont dû contribuer à ce code avant de passer à d'autres projets).

Cela ne fonctionne pas. Notez que <0 or 1> n'est pas un littéral de chaîne; cela signifie un 0 ou 1 (vient généralement de grep -i).

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>
if [ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eqe "0" ]; then ... fi

Il en résulte:

line 322: syntax error near unexpected token `[['

J'ai ensuite essayé:

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>
if [ ([ "$A" -eq "0" ]) || ([ "$B" -ne "0" ]) ] && [ "$C" -eq "0" ]; then ... fi

il en résulte:

line 322: syntax error near unexpected token `[['

Une partie du problème est que les résultats de recherche sont les exemples triviaux, et non les exemples plus complexes avec des conditions composées.

Comment effectuer une simple ((A || B) && C) dans Bash?


Je suis prêt à le dérouler et à répéter les mêmes commandes dans plusieurs blocs:

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>

if [ "$A" -eq "0" ] && [ "$C" -eq "0" ]; then
    ...
Elif [ "$B" -ne "0" ] && [ "$C" -eq "0" ]; then
    ... 
fi
29
user56041

La syntaxe de bash n'est pas de type C, même si une petite partie est inspirée de C. Vous ne pouvez pas simplement essayer d'écrire du code C et vous attendre à ce qu'il fonctionne.

Le point principal d'un Shell est d'exécuter des commandes. La commande open-bracket [ est une commande qui effectue un seul test¹. Vous pouvez même l'écrire sous la forme test (sans le crochet de fermeture final). Le || et && les opérateurs sont des opérateurs Shell, ils combinent des commandes , pas des tests.

Alors quand tu écris

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ]

c'est analysé comme

[ [ "$A" -eq "0" ] ||
[ "$B" -ne "0" ] ] &&
[ "$C" -eq "0" ]

ce qui est le même que

test [ "$A" -eq "0" ||
test "$B" -ne "0" ] &&
test "$C" -eq "0"

Remarquez les parenthèses déséquilibrées? Ouais, ce n'est pas bon. Votre tentative entre parenthèses a le même problème: les crochets parasites.

La syntaxe pour regrouper les commandes est les accolades. La façon dont les accolades sont analysées nécessite une commande complète avant eux, vous devrez donc terminer la commande à l'intérieur des accolades avec une nouvelle ligne ou un point-virgule.

if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then …

Il existe une autre façon d'utiliser des crochets doubles. Contrairement aux crochets simples, les crochets doubles sont une syntaxe Shell spéciale. Ils délimitent expressions conditionnelles . À l'intérieur des crochets doubles, vous pouvez utiliser des parenthèses et des opérateurs comme && et ||. Étant donné que les doubles crochets sont la syntaxe Shell, le Shell sait que lorsque ces opérateurs sont à l'intérieur des crochets, ils font partie de la syntaxe d'expression conditionnelle, pas de la syntaxe de commande Shell standard.

if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then …

Si tous vos tests sont numériques, il existe encore une autre méthode, qui délimite expressions artihmétiques . Les expressions arithmétiques effectuent des calculs entiers avec une syntaxe très semblable à C.

if (((A == 0 || B != 0) && C == 0)); then …

Vous pouvez trouver mon support de bash utile.

[ peut être utilisé en plain sh. [[ et (( sont spécifiques à bash (et ksh et zsh).

¹ Il peut également combiner plusieurs tests avec des opérateurs booléens, mais cela est lourd à utiliser et présente des pièges subtils, donc je ne l'expliquerai pas.

Utilisation [[:

if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ...

Si tu préfères [, les oeuvres suivantes:

if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ...
8
Stephen Kitt

Utilisez le -o opérateur au lieu de votre imbriqué ||. Vous pouvez également utiliser -a pour remplacer && si nécessaire dans vos autres déclarations.

   EXPRESSION1 -a EXPRESSION2
          both EXPRESSION1 and EXPRESSION2 are true

   EXPRESSION1 -o EXPRESSION2
          either EXPRESSION1 or EXPRESSION2 is true


if [  "$A" -eq "0" -o "$B" -ne "0"  ] && [ "$C" -eq "0" ]; then echo success;fi
3
Zachary Brady