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
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
[[ … ]]
is toegevoegd in bash 2.02.((…))
is toegevoegd in bash 2.0.||
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).[[ … ]]
of$((…))
zijn alleen voor groeperen.