Paranteză în aritmetică expr: 3 * (2 + 1)

expr nu pare să placă paranteză (utilizată în matematică la prioritatea explicită a operatorului):

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

Cum se exprimă prioritatea operatorului în bash?

Răspuns

Un alt mod de a utiliza let bash builtin:

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

Notă

Așa cum a subliniat @ Stéphane Chazelas , în bash ar trebui să utilizați ((...)) pentru a face aritmetică peste expr sau let pentru lizibilitate.

Pentru portabilitate, utilizați $((...)) ca Răspuns @Bernhard .

Comentarii

  • +1 Și mai lizibil! Mi-am postat întrebarea + răspunsul doar gândindu-mă că ar fi util pentru colegii mei utilizatori de Linux, dar acum obțin o mulțime de beneficii din celelalte răspunsuri 🙂
  • Acolo ‘ nu are niciun motiv să folosiți let. ‘ nu este mai standard sau mai portabil decât (( a = 3 * (2 + 1) )) (ambele provin de la ksh și sunt disponibile numai în ksh, bash și zsh) și este ‘ mai puțin lizibil sau ușor de citat. Folosiți a=$((3 * (2 + 1))) pentru a fi portabil.
  • Nu ‘ nu spun ‘ greșit, ‘ spun doar că nu ar trebui utilizat deoarece există alternative mai bune (una pentru lizibilitate ((a = 3 * (2 + 1) )), una pentru portabilitate a=$((3 * (2 + 1)))), deci ‘ nu este o notă împotriva dvs. sau a răspunsului dvs., ci împotriva faptului că acesta este răspunsul selectat și cel mai bun marcator .
  • @St é phaneChazelas: Am actualizat răspunsul meu!
  • Am folosit întotdeauna a=1 $[a+2] sau a=1 b=2 $[a+b]. Motivul lor este acela de a evita această sintaxă?

Răspuns

În schimb, puteți utiliza expansiunea aritmetică.

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

În opinia mea personală, acest lucru arată un pic mai frumos decât utilizarea expr.

De la man bash

Extindere aritmetică Expansiunea aritmetică permite evaluarea unei expresii aritmetice și înlocuirea rezultatului. Formatul pentru extinderea aritmetică este:

 $((expression)) 

Expresia este tratată ca și cum ar fi în ghilimele duble, dar ghilimele duble din paranteze nu sunt tratate special. Toate jetoanele din expresie suferă extinderea parametrilor, extinderea șirurilor, substituirea comenzilor și eliminarea citatelor. Extensiile aritmetice pot fi imbricate.

Evaluarea se efectuează conform regulilor enumerate mai jos în EVALUAREA ARITMETICĂ. Dacă expresia este nevalidă, bash imprimă un mesaj care indică eșecul și nu are loc nicio substituire.

Comentarii

  • În afară de lizibilitate, nu necesită, de asemenea, divizarea ‘ pentru a realiza aritmetica; ‘ este gestionat de shell-ul în sine.
  • Rețineți că în shell-urile POSIX, ‘ este supus cuvântului împărțirea, deci este ‘ un obicei bun să îl citez în contexte de listă.
  • Când încerc asta la shell-ul bash, primesc ‘ Nume ilegal al variabilei. ”

Răspuns

Nu există niciun motiv să folosiți expr pentru aritmetică în cochilii moderni.

POSIX definește $((...)) operator de expansiune. Așadar, puteți utiliza acest lucru în toate shell-urile conforme cu POSIX (sh din toate unix-like-urile moderne, dash, bash, yash, mksh, zsh, posh, ksh … ).

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

ksh a introdus, de asemenea, un let este trecut același tip de expresie aritmetică, nu se extinde în ceva, dar returnează o stare de ieșire în funcție de expresia rezolvată este la 0 sau nu, ca în expr:

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

Cu toate acestea, deoarece citarea îl face incomod și nu foarte lizibil (nu în aceeași măsură ca expr desigur), ksh a introdus și un ((...)) formă alternativă:

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

care este mult mai lizibilă și ar trebui folosită în schimb.

let și ((...)) sunt disponibile numai în ksh, zsh și bash.Sintaxa $((...)) ar trebui preferată dacă este necesară portabilitatea către alte shell-uri, expr este necesară doar pentru shell-urile pre-POSIX Bourne (de obicei shell-ul Bourne sau versiunile timpurii ale shell-ului Almquist).

Pe frontul non-Bourne, există câteva shell-uri cu operator aritmetic încorporat:

  • csh / tcsh (de fapt, primul shell Unix cu evaluare aritmetică încorporată):

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

    a = $:"3 * (2 + 1)" 
  • ca notă istorică, versiunea originală a shell-ului Almquist, așa cum a fost postată pe usenet în 1989, avea un expr builtin (de fapt fuzionat cu test), dar a fost eliminat mai târziu.

Comentarii

  • Învăț câte ceva nou în fiecare zi de la tine, St é phane. Apreciez foarte mult cunoștințele dvs. despre POSIX shell!
  • Ce zici de : $((a = a*2))?
  • Ce se întâmplă dacă am un punct mobil? Expresia mea este a = $ ((-14 + 0,2 * (1 + 2 + 3))). Jetonul de eroare este ” .2 * (1 + 2 + 3) ”
  • @Blaise, atunci tu ‘ ar trebui să aibă un shell care acceptă puncte flotante în $((...)) cum ar fi zsh, ksh93 sau yash.

Răspuns

expr este o comandă externă, nu este o sintaxă de shell specială. Prin urmare, dacă doriți ca expr să vadă caractere speciale ale shell-ului, trebuie să le protejați de analizarea shell-ului prin citarea lor. Mai mult, expr are nevoie ca fiecare număr și operator să fie transmis ca parametru separat. Astfel:

expr 3 \* \( 2 + 1 \) 

Dacă nu lucrați la un sistem antic Unix din anii 1970 sau 1980, există foarte puține motive pentru a folosi expr. În trecut, cochilii nu aveau un mod încorporat de a efectua aritmetica și trebuia să apelați utilitarul expr. Toate shell-urile POSIX au aritmetică încorporată prin sintaxa expansiune aritmetică .

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

construct $((…)) se extinde la rezultatul expresiei aritmetice (scrisă în zecimal). Bash, ca majoritatea shell-urilor, acceptă numai modul aritmetic întreg 2 64 (sau modulo 2 32 pentru versiunile mai vechi de bash și alte câteva shell-uri pe mașini pe 32 de biți).

Bash oferă o sintaxă de comoditate suplimentară atunci când doriți să efectuați sarcini sau să testați dacă o expresie este 0, dar nu vă interesează rezultatul. Această construcție există și în ksh și zsh, dar nu și în sh simplu.

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

Pe lângă aritmetica întregului, expr oferă câteva funcții de manipulare a șirurilor. Și acestea sunt subsumate de caracteristicile shell-urilor POSIX, cu excepția uneia: expr STRING : REGEXP testează dacă șirul se potrivește cu regexp-ul specificat. Un shell POSIX nu poate face acest lucru fără instrumente externe, dar bash poate cu [[ STRING =~ REGEXP ]] (cu o sintaxă regexp diferită expr este un instrument clasic și folosește BRE, bash folosește ERE).

Dacă nu rețineți scripturile care rulează pe sisteme vechi de 20 de ani, nu trebuie să știți că expr a existat vreodată. Utilizați aritmetica shell.

Comentarii

  • expr foo : '\(.\)' face și extragerea textului. bash ‘ s BASH_REMATCH realizează ceva similar. De asemenea, face compararea șirurilor, ceea ce POSIX [ nu face (deși s-ar putea imagina modalități de a utiliza sort pentru asta).
  • subliniați ca substituent de sintaxă — sunteți un Schemer, @Giles? :]
  • @RubyTuesdayDONO Nu ‘ nu am folosit un subliniere aici. Citești greșit U + 2026 ELLIPSA ORIZONTALĂ? Dacă da, încercați să utilizați un font mai mare.
  • @Giles – bine, da, arată doar ca un subliniat datorită dimensiunii fontului meu. pentru mine, ” Schemer ” este un complement și ‘ nu este ca elipsa versus subliniere schimbă semnificația oricum … nu este nevoie să te descurci: /

Răspunde

ghilimele:

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

Ghilimelele împiedică bash să interpreteze paranteza ca sintaxă bash.

Comentarii

  • Ceea ce Nicolas ilustrează, dar nu explică este că jetoanele de pe linia de comandă expr trebuie separate prin spații; asa de; de exemplu, expr 3 "*" "(2" "+" "1)" nu va funcționa . (De asemenea, BTW, probabil că nu este nevoie să citați +.)
  • Parantezele nu sunt ‘ t cuvinte cheie precum while și [[, ele ‘ re sintaxă. Dacă ar fi cuvinte cheie, nu ar fi ‘ t interpretate ca atare în argumentele de comandă. Aveți nevoie de ghilimele, astfel încât bash să nu ‘ să le analizeze, ci în schimb să vadă un șir literal.

Răspuns

Dacă aveți bc ..

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

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *