Meerdere logische operatoren, ((A || B) & & C), en “ syntaxisfout bij onverwacht token ”

Ik werk met Bash 3 en ik probeer vormen een voorwaardelijke. In C / C ++ is het doodeenvoudig: ((A || B) && C). In Bash blijkt het niet zo te zijn (ik denk dat de Git-auteurs deze code moeten hebben bijgedragen voordat ze verder gingen met andere inspanningen).

Dit werkt niet. Merk op dat <0 or 1> geen letterlijke tekenreeks is; het betekent een 0 of 1 (komt meestal van 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 

Het resulteert in:

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

Ik probeerde toen:

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

het resulteert in:

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

Een deel van het probleem is dat zoekresultaten de triviale voorbeelden zijn, en niet de meer complexe voorbeelden met samengestelde voorwaarden.

Hoe voer ik een eenvoudige ((A || B) && C) in Bash?


Ik “ben klaar om het gewoon uit te rollen en dezelfde opdrachten in meerdere blokken te herhalen:

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 

Answer

De syntaxis van bash is niet C-achtig, ook al is een klein deel ervan geïnspireerd door C. Je kunt niet simpelweg proberen C-code te schrijven en verwachten dat het werkt.

Het belangrijkste punt van een shell is het uitvoeren van commandos. Het open-bracket-commando [ is een commando dat een enkele test uitvoert¹. U kunt het zelfs schrijven als test (zonder de laatste sluitende haak). De || en && operators zijn shell-operators, ze combineren commandos , geen tests.

Dus als je schrijft

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

dat “wordt geparseerd als

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

welke is hetzelfde als

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

Let op de ongebalanceerde haakjes? Ja, dat is niet goed. Uw poging tussen haakjes heeft hetzelfde probleem: valse haakjes.

De syntaxis om opdrachten samen te groeperen is accolades. De manier waarop accolades worden geparseerd, vereist een volledig commando ervoor, dus je zult “het commando tussen accolades moeten beëindigen met een nieuwe regel of puntkomma.

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

Daar Dit is een alternatieve manier om dubbele beugels te gebruiken. In tegenstelling tot enkele haakjes zijn dubbele haakjes speciale shell-syntaxis. Ze begrenzen voorwaardelijke uitdrukkingen . Tussen dubbele haakjes kunt u haakjes en operatoren gebruiken zoals && en ||. Aangezien de dubbele haakjes de shell-syntaxis zijn, weet de shell dat wanneer deze operatoren tussen haakjes staan, ze “deel uitmaken van de syntaxis van de voorwaardelijke expressie, niet van de gewone syntaxis van het shell-commando.

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

Als al uw tests numeriek zijn, is er nog een andere manier om artihmetische uitdrukkingen te begrenzen. Rekenkundige uitdrukkingen voeren berekeningen met gehele getallen uit met een zeer C-achtige syntaxis.

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

Misschien vindt u mijn bash-haakje primer nuttig.

[ kan worden gebruikt in gewone sh. [[ en (( zijn specifiek voor bash (en ksh en zsh).

¹ Het kan ook combineer meerdere tests met booleaanse operatoren, maar dit is omslachtig in het gebruik en heeft subtiele valkuilen, dus ik zal het niet uitleggen.

Reacties

  • Bedankt Giles. Geldt dit voor Bash 2 tot en met Bash 4? Ik heb iets licht overdraagbaarheid nodig, maar Kusalananda zei dat sommige dingen die ik niet deed, draagbaar zijn (betekent dit dat wat ik aan het doen ben niet draagbaar?). Hier betekent mild Bash 2 tot en met Bash 4.
  • @jww [[ … ]] is toegevoegd in bash 2.02. ((…)) is toegevoegd in bash 2.0.
  • @Giles – bedankt. Bash 2 is waarschijnlijk lachwekkend voor de meesten. Het is te wijten aan ons bestuur en onwil om oudere platforms te verlaten. Bash 2 en GCC 3 verschijnen tijdens onze Fedora 1-tests. We zullen af en toe een ouder platform laten gaan, maar daar moeten redenen voor zijn. We don ' abonneer u op het beleid van Apple, Microsoft, Mozilla, enz. met betrekking tot verlatenware.
  • @jww Begrijp alsjeblieft dat de voorrang van || en && verandering van [ naar [[ en ((. Gelijke prioriteit in [ (gebruik haakjes om de volgorde van evaluatie te bepalen), maar & & heeft hogere prioriteit in [[ en (( dan || (zoals in C).
  • @Roland Nee, haakjes tussen [[ … ]] of $((…)) zijn alleen voor groeperen.

Antwoord

Gebruik [[:

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

Als u de voorkeur geeft aan [, werkt het volgende:

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

Reacties

  • Bedankt, Stephen. In mijn geval heb ik dus je eerste voorbeeld gebruikt … regex = ' ^ [0-9] + $ ' length = $ {#datearg} als! [[$ datearg = ~ $ regex & & $ length -eq 8]]; dan echo " fout: niet een aantal van 8 "; fi

Answer

Gebruik de operator -o in plaats van uw genest ||. U kunt ook -a gebruiken om & & te vervangen indien nodig in uw andere instructies .

 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 

Reacties

  • Bedankt. Ik kwam de -a en -o tegen, maar ik heb er niet mee geëxperimenteerd. Iemand op Stack Overflow zei om het te vermijden. Ik was het meestal met hen eens, aangezien het script minder leesbaar is door ze te gebruiken.
  • … maar draagbaarder.
  • @Kusalananda – Bedankt voor de heads-ups over draagbaarheid. Het script moet draaien op systemen met Bash 2 tot en met Bash 4. Zal [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]] er problemen mee hebben?
  • Er zullen geen problemen zijn zolang je je aan bash of een andere shell die [[ ... ]] begrijpt.
  • De keerzijde van het gebruik van -a is dat het niet ' t kortsluiting als de eerste uitdrukking vals is. Dus als u vertrouwt op kortsluiting om te voorkomen dat een mogelijk fatale 2e uitdrukking wordt uitgevoerd, kunt u -a niet gebruiken. Voorbeeld: pastebin.com/zM77TXW1

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *