Lausekkeen aritmeettiset sulut: 3 * (2 + 1)

expr ei näytä pitävän suluista (käytetty matematiikassa operaattorin prioriteetin selvittämiseksi):

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

Kuinka ilmaista operaattorin prioriteetti bashissa?

Vastaa

Toinen tapa käyttää let bash sisäänrakennettua:

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

Huomaa

Kuten @ Stéphane Chazelas huomautti , bash -kohdassa sinun tulisi käyttää ((...)) -kohtaa aritmeettiseen kohtaan expr tai let luettavuus.

Siirrettävyydelle käytä $((...)), kuten @Bernhard vastaus .

kommentit

  • +1 vieläkin luettavampi! Lähetin kysymykseni + vastauksen ajattelemalla, että siitä olisi hyötyä muille Linux-käyttäjille, mutta nyt saan paljon hyötyä muista vastauksista 🙂
  • Siellä ’ ei ole syytä käyttää let. Se ’ ei ole enää vakio tai kannettava kuin (( a = 3 * (2 + 1) )) (molemmat tulevat ksh ja ovat saatavana vain tiedostoina ksh, bash ja zsh), ja se on ’ vähemmän luettavissa tai helppo lainata. Käytä kannettavaa a=$((3 * (2 + 1))).
  • I ’ m en sano sitä ’ s väärin, minä ’ m vain sanon, että sitä ei pitäisi käyttää, koska on parempia vaihtoehtoja (yksi luettavuus ((a = 3 * (2 + 1) )), yksi siirrettävyyden kannalta a=$((3 * (2 + 1)))), joten se ’ ei ole huomautus sinua tai vastaustasi vastaan, mutta sitä vastaan, että se on valittu vastaus ja paras maalintekijä .
  • @St é phaneChazelas: Päivitin vastaukseni!
  • Olen aina käyttänyt a=1 $[a+2] tai a=1 b=2 $[a+b]. Onko heidän syytä välttää tätä syntaksia?

Vastaus

Voit käyttää sen sijaan aritmeettista laajennusta.

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

Minun mielestäni tämä näyttää hiukan mukavammalta kuin expr.

Lähettäjä man bash

Aritmeettinen laajennus Aritmeettinen laajennus mahdollistaa aritmeettisen lausekkeen arvioinnin ja tuloksen korvaamisen. Aritmeettisen laajennuksen muoto on:

 $((expression)) 

Lauseketta käsitellään ikään kuin se olisi lainausmerkkien sisällä, mutta sulkeissa olevaa kaksoislainausta ei käsitellä erikseen. Kaikki lausekkeen tunnukset läpikäyvät parametrien laajentamisen, merkkijonolaajennuksen, komentojen korvaamisen ja lainausten poistamisen. Aritmeettiset laajennukset voidaan sijoittaa sisäkkäin.

Arviointi suoritetaan alla ARITMEETTISEN ARVIOINNIN alla lueteltujen sääntöjen mukaisesti. Jos lauseke on virheellinen, bash tulostaa epäonnistuneen viestin eikä korvaamista tapahdu.

Kommentit

  • Luettavuuden lisäksi se ei myöskään vaadi ’ haaroittamista ylimääräiseen prosessiin aritmeettisen tekemiseksi; Kuori itse käsittelee sen ’.
  • Huomaa, että POSIX-kuorissa se ’ kuuluu sanaan jakaminen, joten ’ on hyvä tapa lainata sitä luetteloyhteyksissä.
  • Kun yritän tätä bash-kuoressa, saan ’ Laiton muuttujan nimi. ”

Vastaa

Ei ole syytä käyttää expr aritmeettiseen toimintaan nykyaikaisissa kuorissa.

POSIX määrittelee $((...)) Laajennusoperaattori. Voit siis käyttää sitä kaikissa POSIX-yhteensopivissa kuoreissa (kaikkien nykyisten Unix-tykkäysten, dash, bash, yash, mksh, zsh, posh, ksh sh). ).

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

ksh esitteli myös sisäänrakennetun let on läpäissyt samanlaisen aritmeettisen lausekkeen, ei laajene mihinkään, mutta palauttaa poistumistilan sen perusteella, onko lauseke resolv es 0: een tai ei, kuten expr:

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

Koska lainaus tekee siitä hankalan eikä hyvin luettavissa (ei tietyssä määrin kuin expr tietysti), ksh esitteli myös ((...)) vaihtoehtoinen muoto:

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

joka on paljon luettavampi ja jota tulisi käyttää sen sijaan.

let ja ((...)) ovat käytettävissä vain ksh, zsh ja bash.$((...)) -syntaksia tulisi suositella, jos siirrettävyys muihin kuoreihin tarvitaan, expr tarvitaan vain pre-POSIX Bourne-tyyppisille kuoreille (yleensä Bourne-kuori tai Almquist-kuoren varhaiset versiot).

Ei-Bourne-rintamalla on muutama kuori, joissa on sisäänrakennettu aritmeettinen operaattori:

  • csh / tcsh (oikeastaan ensimmäinen Unix-kuori, johon on sisäänrakennettu aritmeettinen arviointi):

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

    a = $:"3 * (2 + 1)" 
  • historian muistiinpanona Almquist-kuoren alkuperäisellä versiolla, joka julkaistiin Usenetissä vuonna 1989, oli expr sisäänrakennettu (tosiasiallisesti yhdistetty test: iin), mutta se poistettiin myöhemmin.

Kommentit

  • Opin sinulta joka päivä jotain uutta, St é phane. Arvostan suuresti POSIX-komentotulkkiasi!
  • Entä : $((a = a*2))?
  • Entä jos minulla on liukuluku? Lausekkeeni on a = $ ((-14 + 0,2 * (1 + 2 + 3))). Virhetunnus on ” .2 * (1 + 2 + 3) ”
  • @Blaise, sitten sinä ’ d tarvitsee kuoren, joka tukee kelluvia kohtia $((...)), kuten zsh, ksh93 tai yash.

Vastaus

expr on ulkoinen komento, se ei ole erityinen kuoren syntakse. Siksi, jos haluat expr nähdäksesi kuoren erikoismerkit, sinun on suojattava niitä kuoren jäsentämiseltä lainaamalla niitä. Lisäksi expr edellyttää, että jokainen numero ja operaattori välitetään erillisenä parametrina. Siten:

expr 3 \* \( 2 + 1 \) 

Ellei työskentele antiikkisen unix-järjestelmän parissa 1970- tai 1980-luvuilla, ei ole juurikaan syytä käyttää expr. Vanhoina aikoina kuoreilla ei ollut sisäänrakennettua tapaa suorittaa laskutoimitusta, ja sinun oli sen sijaan soitettava expr -apuohjelmaan. Kaikissa POSIX-kuoreissa on sisäänrakennettu aritmeettinen aritmeettisen laajennuksen syntaksin kautta.

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

konstrukti $((…)) laajenee aritmeettisen lausekkeen tulokseen (kirjoitettu desimaalilla). Bash, kuten useimmat komentotulkit, tukee vain kokonaislukuaritmeettista modulo 2 64 (tai modulo 2 32 vanhemmille bash-versioille ja joillekin muille 32-bittisten koneiden kuorille).

Bash tarjoaa mukavuussyntaksin , kun haluat suorittaa tehtäviä tai testata, onko lauseke 0, mutta älä välitä tuloksesta. Tämä rakenne on myös ksh: ssä ja zsh: ssä, mutta ei tavallisessa sh: ssä.

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

Lukuaritmeettisen lisäksi expr tarjoaa muutaman merkkijonon manipulointitoiminnon. Nämäkin ovat POSIX-kuorien ominaisuuksien alaisia, lukuun ottamatta yhtä: expr STRING : REGEXP testaa, vastaako merkkijono määritettyä regexp-arvoa. POSIX-kuori ei voi tehdä tätä ilman ulkoisia työkaluja, mutta bash voi käyttää [[ STRING =~ REGEXP ]] ( erilaisella regexp-syntaksilla expr on klassinen työkalu, joka käyttää BRE: tä, bash käyttää ERE: tä).

Ellet skriptejä korjaa uudelleen jotka toimivat 20-vuotiailla järjestelmillä, sinun ei tarvitse tietää, että expr on koskaan ollut olemassa. Käytä kuoriaritmeettista.

Kommentit

  • expr foo : '\(.\)' myös purkaa tekstiä. bash ’ s BASH_REMATCH saavuttaa jotain vastaavaa. Se tekee myös merkkijonojen vertailua, jota POSIX [ ei tee (vaikka voisi kuvitella tapoja käyttää sort siihen).
  • alleviivaus syntaksin paikkamerkkinä — sinä Schemer, @Giles? :]
  • @RubyTuesdayDONO En käyttänyt ’ t alleviivaa tässä. Luetko väärin U + 2026 HORIZONTAL ELLIPSIS -ohjelmaa? Jos näin on, kokeile käyttää isompaa kirjasinta.
  • @Giles – okei, kyllä, se näyttää vain alaviivalta kirjasinkoon takia. minulle ” Schemer ” on täydennysosa, ja se ’ ei pidä ellipsistä versus alleviiva muuttaa merkitystä joka tapauksessa … ei tarvitse olla harmaantunut sen suhteen: /

Vastaa

Käytä sulkeita lainaukset:

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

Lainausmerkit estävät bashia tulkitsemasta sulkeita bash-syntaksina.

Kommentit

  • Nicolas kuvaa, mutta ei selitä, että komentorivillä expr olevat tunnukset on erotettava välilyönneillä; niin; esimerkiksi expr 3 "*" "(2" "+" "1)" ei toimi . (BTW: n lisäksi sinun ei todennäköisesti tarvitse lainata + -merkkiä.)
  • Suluissa ei ole ’ t avainsanoja, kuten while ja [[, ne ’ syntaksi uudelleen. Jos ne olisivat avainsanoja, niitä ei tulkita ’ sellaisiksi komentoargumenteissa. Tarvitset lainausmerkkejä, jotta bash ei jäsennä niitä ’ t, vaan näkee merkkijonon kirjaimen.

Vastaa

Jos sinulla on bc ..

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

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *