Plusieurs opérateurs logiques, ((A || B) & & C) et “ erreur de syntaxe près du jeton inattendu ”

Je « travaille avec Bash 3 et jessaye de forme un conditionnel. En C / C ++, cest très simple: ((A || B) && C). Dans Bash, ce nest pas le cas (je pense que les auteurs de Git doivent avoir contribué à ce code avant de passer à dautres projets).

Cela ne fonctionne pas. Notez que <0 or 1> nest pas une chaîne littérale; cela signifie un 0 ou un 1 (provient 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 `[[" 

Jai 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 puis-je effectuer un 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 

Réponse

La syntaxe de bash nest pas de type C, même si une petite partie de celle-ci est inspirée de C. Vous ne pouvez pas simplement essayer décrire du code C et vous attendre à ce quil fonctionne.

Le point principal dun shell est dexé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). Les opérateurs || et && sont des opérateurs shell, ils combinent des commandes et non des tests.

Ainsi, lorsque vous écrivez

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

cela « est analysé comme

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

qui est le même que

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

Vous avez remarqué que les crochets sont déséquilibrés? Ouais, ce nest pas bon. Votre tentative avec des parenthèses a le même problème: des crochets faux.

La syntaxe pour regrouper les commandes est des accolades. La façon dont les accolades sont analysées nécessite une commande complète avant elles, vous devrez donc terminer la commande entre les accolades par un saut de ligne ou un point-virgule.

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

Là « est une autre manière dutiliser des doubles crochets. Contrairement aux crochets simples, les doubles crochets sont une syntaxe spéciale du shell. Ils délimitent les expressions conditionnelles . À lintérieur de doubles crochets, vous pouvez utiliser des parenthèses et des opérateurs comme && et ||. Étant donné que les doubles crochets sont une syntaxe shell, le shell sait que lorsque ces opérateurs sont entre crochets, ils « font partie de la syntaxe dexpression conditionnelle, pas de la syntaxe de commande shell ordinaire.

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

Si tous vos tests sont numériques, il existe encore une autre manière de délimiter les expressions artihmétiques . Les expressions arithmétiques effectuent des calculs dentiers avec une syntaxe très semblable au C.

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

Vous pouvez trouver mon crochet bash primer utile.

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

¹ Cela peut aussi combinez plusieurs tests avec des opérateurs booléens, mais cela est fastidieux à utiliser et présente des pièges subtils, donc je ne vais pas lexpliquer.

Commentaires

  • Merci Giles. Est-ce que cela vaut pour Bash 2 à Bash 4? Jai besoin de quelque chose de portabilité modérée, mais Kusalananda a mentionné que certaines choses que je ne faisais pas sont portables (cela signifie-t-il que ce que je fais est pas portable?). Ici, moyennement signifie Bash 2 à Bash 4.
  • @jww [[ … ]] a été ajouté dans bash 2.02. ((…)) a été ajouté dans bash 2.0.
  • @Giles – merci. Bash 2 est probablement risible pour la plupart. Cest à cause de notre gouvernance et de notre réticence dabandonner les anciennes plates-formes. Bash 2 et GCC 3 apparaissent lors de nos tests Fedora 1. Nous laisserons une plate-forme plus ancienne fonctionner à loccasion, mais il doit y avoir des raisons à cela. Nous ne ' t vous abonner à la politique dabandonware dApple, Microsoft, Mozilla, etc.
  • @jww Veuillez comprendre que la priorité de || et && passer de [ à [[ et ((. Égal à priorité dans [ (utilisez des parenthèses pour contrôler lordre dévaluation), mais & & a une priorité plus élevée dans [[ et (( que || (comme en C).
  • @Roland Non, parenthèses entre [[ … ]] ou $((…)) sont juste pour le regroupement.

Réponse

Utilisez [[:

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

Si vous préférez [, ce qui suit fonctionne:

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

Commentaires

  • Merci, Stephen. Dans mon cas, jai utilisé votre premier exemple ainsi … regex = ' ^ [0-9] + $ ' length = $ {#datearg} si! [[$ datearg = ~ $ regex & & $ length -eq 8]]; then echo " erreur: pas un nombre de lenth de 8 "; fi

Réponse

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

 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 

Commentaires

  • Merci. Je suis tombé sur les -a et -o, mais je ne les ai pas expérimentés. Quelquun sur Stack Overflow a dit de léviter. Jétais généralement daccord avec eux car le script est moins lisible en les utilisant.
  • … mais plus portable.
  • @Kusalananda – Merci pour les avertissements sur la portabilité. Le script doit sexécuter sur les systèmes avec Bash 2 à Bash 4. Est-ce que [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]] rencontrera des problèmes avec eux?
  • Il ny aura aucun problème tant que vous vous en tenez à bash ou tout autre shell qui comprend [[ ... ]].
  • Linconvénient de lutilisation de -a est quil ne le fait pas ' t court-circuit si la première expression est fausse. Donc, si vous comptez sur un court-circuit pour empêcher une deuxième expression fatale potentielle de sexécuter, vous ne pouvez pas utiliser -a. Exemple: pastebin.com/zM77TXW1

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *