Bash ' s voorwaardelijke operator en toewijzing

Kunnen we de voorwaardelijke operator van bash gebruiken met toewijzingsoperatoren na dubbele punt?

Bash-referentiehandleiding legt de rekenkundige operatoren als volgt uit.

  • conditionele operator expr ? expr : expr
  • toewijzing = *= /= %= += -= <<= >>= &= ^= |=

Ten eerste lijkt deze code goed te werken:

a=1; ((a? b=1 : 2 )) #seems to work 

Maar als ik toewijzingsoperatoren gebruik na :, kreeg ik een “poging tot toewijzing aan niet-variabele” fout:

a=1; ((a? b=1 : c=1)) #attempted assignment to non-variable error 

Waarom kunnen we alleen toewijzingsoperatoren gebruiken vóór dubbele punt?

Opmerkingen

  • Het kan leuk zijn om variabeletoekenningen uit te voeren met de voorwaardelijke operator, maar het ' maakt je code zeer onleesbaar. Ik ' geef de voorkeur aan ((a)) && b=1 || c=1
  • @devnull Ik denk dat de code ' De leesbaarheid hangt het meest af van wie het leest. Toch kan het waar zijn wat je zegt, maar ik ' heb ternary operators getest in dash, zsh, sh en bash en ze gedragen zich allemaal hetzelfde, ondanks dat ze niet gespecificeerd zijn door POSIX. Uw voorbeeld werkt alleen in bash en zsh voor zover ik weet. Dit is echter POSIX-vriendelijk: ( : ${a?} ) && b=1 || c=1. Ik vind het ook veel gemakkelijker om te lezen dan ternary of je eigen voorbeeld.

Antwoord

Bash parseert je laatste commando als

a=1; (( (a? b=1 : c)=1 )) 

wat duidelijk zou moeten maken waarom het niet werkt. In plaats daarvan moet je

a=1; (( a? b=1 : (c=1) )) 

Answer

gebruiken Dit wordt een ternary assignment expressie. Hier “een stukje uit een ander antwoord van mij:

% a=abc % b=abcd % t=10 ; f=5 % echo $((r=${#a}>${#b}?t:f)) ; echo $r > 5 > 5 % echo $((r=${#a}<${#b}?t:f)) ; echo $r > 10 > 10 

Je ziet, zoals je zegt, dit is een voorwaardelijke toewijzingsoperatie. Het hangt af van de voorwaarden. De syntaxis werkt als volgt:

$((var = $condition <compare_operator> $condition \ ?if $true_assign :or $false_assign )) 

Ik geloof niet dat u dit correct gebruikt.

Van wikipedia :

?: wordt gebruikt als volgt:

condition ? value_if_true : value_if_false

De voorwaarde wordt als waar of onwaar geëvalueerd als een Booleaanse uitdrukking. Op basis van de evaluatie van de Booleaanse voorwaarde retourneert de volledige uitdrukking waarde_if_waar als voorwaarde waar is, maar waarde_als_waaraan anders. Gewoonlijk moeten de twee subuitdrukkingen value_if_true en value_if_false hetzelfde type hebben, wat het type van de hele uitdrukking bepaalt. Het belang van deze typecontrole ligt in het meest voorkomende gebruik van de operator – in voorwaardelijke toewijzingsinstructies. In dit gebruik verschijnt het als een uitdrukking aan de rechterkant van een toewijzingsinstructie, als volgt:

variable = condition ? value_if_true : value_if_false

De ?: operator is vergelijkbaar met de manier waarop voorwaardelijke expressies (if-then-else constructies) werken in functionele programmeertalen, zoals Scheme, ML en Haskell, aangezien if-then-else een expressie in plaats van een statement in die talen.

Ik denk dat uw specifieke probleem hiermee verband houdt:

Net als in de if-else-constructie wordt slechts één van de uitdrukkingen “x” en “y” geëvalueerd.

Als u de bovenstaande link leest op ternary uitdrukkingen je zult die evaluatie zien n is kortgesloten, dus uw toewijzing aan de false -zijde fouten omdat 1 = true.

In ieder geval maakt het niet uit te veel omdat ik niet denk dat dit doet wat je denkt dat het doet.

Answer

Ternaire operatoren retourneren een waarde gebaseerd op een toets. Ze worden niet gebruikt voor vertakkingen.

Hier is een manier om een pseudo-ternaire operator voor bash te krijgen (let op de back-ticks):

$result=`[ < condition > ] && echo "true-result" || echo "false-result" `

$ a= $ c=`[ $a ] && echo 1 || echo 0` $ echo $c 0 $ a=5 $ c=`[ $a ] && echo 1 || echo 0` $ echo $c 1

Geef een reactie

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