Haakjes in expr rekenkunde: 3 * (2 + 1)

expr lijkt niet op haakjes te staan (gebruikt in wiskunde naar expliciete operatorprioriteit):

expr 3 * (2 + 1) bash: syntax error near unexpected token `(" 

Hoe operatorprioriteit uitdrukken in bash?

Antwoord

Een andere manier om let bash ingebouwd te gebruiken:

$ let a="3 * (2 + 1)" $ printf "%s\n" "$a" 9 

Opmerking

Zoals @ Stéphane Chazelas opmerkte , in bash moet u ((...)) gebruiken om te rekenen met expr of let voor leesbaarheid.

Gebruik voor portabiliteit $((...)) zoals @Bernhard antwoord .

Reacties

  • +1 Nog beter leesbaar! Ik heb mijn vraag + antwoord gepost met de gedachte dat het nuttig zou zijn voor mijn mede Linux-gebruikers, maar nu haal ik veel voordeel uit de andere antwoorden 🙂
  • Daar ‘ s geen reden om let te gebruiken. Het ‘ is niet meer standaard of draagbaar dan (( a = 3 * (2 + 1) )) (beide zijn afkomstig van ksh en zijn alleen beschikbaar in ksh, bash en zsh) en is ‘ minder leesbaar of gemakkelijk te citeren. Gebruik a=$((3 * (2 + 1))) om draagbaar te zijn.
  • Ik ‘ m niet zeggen ‘ is fout, ik ‘ m zeg maar dat het niet gebruikt mag worden omdat er betere alternatieven zijn (een voor leesbaarheid ((a = 3 * (2 + 1) )), een voor overdraagbaarheid a=$((3 * (2 + 1)))), dus ‘ is geen opmerking tegen jou of je antwoord, maar tegen het feit dat het het geselecteerde antwoord en de topscorer is .
  • @St é phaneChazelas: mijn antwoord bijgewerkt!
  • Ik heb altijd a=1 $[a+2] of a=1 b=2 $[a+b]. Is hun reden om die syntaxis te vermijden?

Antwoord

Je kunt in plaats daarvan de rekenkundige uitbreiding gebruiken.

echo "$(( 3 * ( 2 + 1 ) ))" 9 

Naar mijn persoonlijke mening ziet dit er een beetje leuker uit dan expr te gebruiken.

Van man bash

Rekenkundige uitbreiding Rekenkundige uitbreiding maakt het mogelijk een rekenkundige uitdrukking te evalueren en het resultaat te vervangen. Het formaat voor rekenkundige uitbreiding is:

 $((expression)) 

De uitdrukking wordt behandeld alsof deze tussen dubbele aanhalingstekens staat, maar dubbele aanhalingstekens tussen haakjes worden niet speciaal behandeld. Alle tokens in de uitdrukking ondergaan parameteruitbreiding, tekenreeksuitbreiding, opdrachtvervanging en verwijdering van aanhalingstekens. Rekenkundige uitbreidingen kunnen worden genest.

De evaluatie wordt uitgevoerd volgens de regels die hieronder worden vermeld onder ARITMETISCHE EVALUATIE. Als expressie ongeldig is, drukt bash een bericht af dat aangeeft dat er een fout is opgetreden en dat er geen vervanging plaatsvindt.

Reacties

  • Afgezien van de leesbaarheid, heeft het ‘ ook geen extra proces nodig om de berekeningen uit te voeren; it ‘ wordt afgehandeld door de shell zelf.
  • Merk op dat het in POSIX-shells ‘ s onderhevig is aan woord splitsen, dus ‘ is een goede gewoonte om het in lijstcontexten te citeren.
  • Als ik dit probeer in de bash-shell, krijg ik ‘ Ongeldige variabelenaam. ”

Antwoord

Er is geen reden om expr te gebruiken voor rekenkunde in moderne shells.

POSIX definieert de $((...)) expansie-operator. Dus je kunt dat gebruiken in alle POSIX-compatibele shells (de sh van alle moderne Unix-likes, dash, bash, yash, mksh, zsh, posh, ksh … ).

a=$(( 3 * (2 + 1) )) a=$((3*(2+1))) 

ksh introduceerde ook een let ingebouwd waarin dezelfde soort rekenkundige uitdrukking wordt doorgegeven, breidt zich niet uit in iets maar retourneert een exitstatus op basis van of de uitdrukking resolv es naar 0 of niet, zoals in expr:

if let "a = 3 * (2 + 1)"; then echo "$a is non-zero" fi 

Omdat het citeren het echter lastig maakt en niet zeer leesbaar (niet in dezelfde mate als expr natuurlijk), ksh introduceerde ook een ((...)) alternatieve vorm:

if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then echo "$a is non-zero and 3 > 1" fi ((a+=2)) 

die veel beter leesbaar is en in plaats daarvan moet worden gebruikt.

let en ((...)) zijn alleen beschikbaar in ksh, zsh en bash.De $((...)) syntaxis verdient de voorkeur als portabiliteit naar andere shells nodig is, expr is alleen nodig voor pre-POSIX Bourne-achtige shells (meestal de Bourne-shell of vroege versies van de Almquist-shell).

Op het niet-Bourne-front zijn er een paar shells met ingebouwde rekenkundige operator:

  • csh / tcsh (eigenlijk de eerste Unix-shell met ingebouwde rekenkundige evaluatie):

    @ a = 3 * (2 + 1) 
  • akanga (gebaseerd op rc)

    a = $:"3 * (2 + 1)" 
  • als een geschiedenisnotitie had de originele versie van de Almquist-shell, zoals gepost op usenet in 1989 een expr ingebouwd (eigenlijk samengevoegd met test), maar het is later verwijderd.

Reacties

  • Ik leer elke dag iets nieuws van jou, St é phane. Ik stel uw kennis van POSIX-shell zeer op prijs!
  • Hoe zit het met : $((a = a*2))?
  • Wat moet ik doen als ik een zwevende komma heb? Mijn uitdrukking is a = $ ((-14 + 0.2 * (1 + 2 + 3))). Het fouttoken is ” .2 * (1 + 2 + 3) ”
  • @Blaise, en jij ‘ had een shell nodig die drijvende kommas ondersteunt in $((...)) zoals zsh, ksh93 of yash.

Answer

expr is een extern commando, het is geen speciale shell-syntaxis. Daarom, als je wilt dat expr speciale shell-tekens ziet, moet je ze beschermen tegen shell-parsing door ze aan te halen. Bovendien moet voor expr elk nummer en elke operator worden doorgegeven als een afzonderlijke parameter. Dus:

expr 3 \* \( 2 + 1 \) 

Tenzij u “werkt aan een antiek Unix-systeem uit de jaren 70 of 80, is er weinig reden om . Vroeger hadden shells” geen ingebouwde manier om rekenkundige bewerkingen uit te voeren, en moest je in plaats daarvan het expr hulpprogramma aanroepen. Alle POSIX-shells hebben ingebouwde rekenkunde via de rekenkundige uitbreiding syntaxis.

echo "$((3 * (2 + 1)))" 

De construct $((…)) breidt uit naar het resultaat van de rekenkundige uitdrukking (geschreven in decimaal). Bash ondersteunt, zoals de meeste shells, alleen integer rekenkundige modulo 2 64 (of modulo 2 32 voor oudere versies van bash en enkele andere shells op 32-bit machines).

Bash biedt een extra gemakssyntaxis wanneer je opdrachten wilt uitvoeren of wilt testen of een uitdrukking 0 is maar het resultaat niet kan schelen. Deze constructie bestaat ook in ksh en zsh, maar niet in gewone sh.

((x = 3 * (2+1))) echo "$x" if ((x > 3)); then … 

Naast rekenen met gehele getallen, expr biedt een aantal stringmanipulatiefuncties. Ook deze worden ondergebracht in functies van POSIX-shells, behalve één: expr STRING : REGEXP test of de string overeenkomt met de opgegeven regexp. Een POSIX-shell kan dit niet doen zonder externe tools, maar bash kan met [[ STRING =~ REGEXP ]] (met een verschillende regexp-syntaxis expr is een klassieke tool en gebruikt BRE, bash gebruikt ERE).

Tenzij u “scripts onderhoudt die draaien op 20 jaar oude systemen, je hoeft niet te weten dat expr ooit heeft bestaan. Gebruik shell rekenkunde.

Reacties

  • expr foo : '\(.\)' doet ook tekstextractie. bash ‘ s BASH_REMATCH bereikt iets soortgelijks. Het doet ook stringvergelijking, wat POSIX [ niet doet (hoewel men zich manieren kan voorstellen om sort daarvoor te gebruiken).
  • onderstreping als tijdelijke aanduiding voor de syntaxis — u een Schemer, @Giles? :]
  • @RubyTuesdayDONO Ik heb ‘ geen onderstrepingsteken hier gebruikt. Lees je U + 2026 HORIZONTALE ELLIPSIS verkeerd? Als dat zo is, probeer dan een groter lettertype.
  • @Giles – oké, ja, het ziet er alleen uit als een onderstrepingsteken vanwege mijn lettergrootte. voor mij is ” Schemer ” een aanvulling, en ‘ is niet zoals weglatingsteken versus onderstrepingsteken verandert hoe dan ook de betekenis … het is niet nodig om er snauw over te doen: /

Antwoord

Gebruik haakjes met quotes:

expr 3 "*" "(" 2 "+" 1 ")" 9 

De aanhalingstekens voorkomen dat bash de haakjes interpreteert als bash-syntaxis.

Opmerkingen

  • Wat Nicolas illustreert maar niet uitlegt, is dat de tokens op de expr opdrachtregel moeten worden gescheiden door spaties; zo; expr 3 "*" "(2" "+" "1)" zal bijvoorbeeld niet werken . (Trouwens, je hoeft waarschijnlijk niet de +.)
  • De haakjes zijn ‘ t zoekwoorden zoals while en [[, ze ‘ opnieuw syntaxis. Als het sleutelwoorden waren, zouden ze niet ‘ als zodanig worden geïnterpreteerd in opdrachtargumenten. Je hebt aanhalingstekens nodig zodat bash ze niet ‘ ontleedt, maar in plaats daarvan een letterlijke tekenreeks ziet.

Antwoord

Als je bc ..

echo "3 * (2 + 1)"|bc 9 

Geef een reactie

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