Parentes i tidligere regning: 3 * (2 + 1)

expr ser ikke ut til å like parentes (brukt i matematikk til eksplisitt operatørprioritet):

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

Hvordan uttrykker operatørprioritet i bash?

Svar

En annen måte å bruke let bash innebygd:

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

Merk

Som @ Stéphane Chazelas påpekte , i bash bør du bruke ((...)) for å gjøre regning over expr eller let for lesbarhet.

For bærbarhet, bruk $((...)) som @Bernhard svar .

Kommentarer

  • +1 Enda mer leselig! Jeg la ut spørsmålet mitt + svaret og bare tenkte at det ville være nyttig for mine andre Linux-brukere, men nå får jeg mye utbytte av de andre svarene 🙂
  • Der ‘ er ingen grunn til å bruke let. Det ‘ er ikke noe mer standard eller bærbart enn (( a = 3 * (2 + 1) )) (begge kommer fra ksh og er bare tilgjengelig i ksh, bash og zsh) og det ‘ er mindre leselig eller lett å sitere. Bruk a=$((3 * (2 + 1))) for å være bærbar.
  • Jeg ‘ m ikke si det ‘ er feil, jeg ‘ Jeg sier bare at den ikke skal brukes, da det er bedre alternativer (en for lesbarhet ((a = 3 * (2 + 1) )), en for bærbarhet a=$((3 * (2 + 1)))), så det ‘ er ikke et notat mot deg eller ditt svar, men mot at det er valgt svar og toppscorer .
  • @St é phaneChazelas: Oppdaterte svaret mitt!
  • Jeg har alltid brukt a=1 $[a+2] eller a=1 b=2 $[a+b]. Er deres grunn til å unngå denne syntaksen?

Svar

Du kan bruke den aritmetiske utvidelsen i stedet.

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

Etter min personlige mening ser dette litt finere ut enn å bruke expr.

Fra man bash

Aritmetisk utvidelse Aritmetisk utvidelse tillater evaluering av et aritmetisk uttrykk og erstatning av resultatet. Formatet for aritmetisk utvidelse er:

 $((expression)) 

Uttrykket behandles som om det var innenfor dobbelt anførselstegn, men et dobbelt anførsel innenfor parentes blir ikke behandlet spesielt. Alle tokens i uttrykket gjennomgår parameterutvidelse, strengutvidelse, kommandosubstitusjon og fjerning av sitat. Aritmetiske utvidelser kan være nestet.

Evalueringen utføres i henhold til reglene som er oppført nedenfor under ARITMETISK EVALUERING. Hvis uttrykket er ugyldig, skriver bash ut en melding som indikerer feil og ingen erstatning forekommer.

Kommentarer

  • Bortsett fra lesbarhet, krever det ikke ‘ det kreves en ekstra prosess for å gjøre regningen; det ‘ håndteres av selve skallet.
  • Merk at i POSIX-skall er det ‘ underlagt ordet splitting, så det ‘ er en god vane å sitere det i listesammenhenger.
  • Når jeg prøver dette på bash-skallet får jeg ‘ Ulovlig variabelnavn. »

Svar

Det er ingen grunn til å bruke expr for regning i moderne skjell.

POSIX definerer $((...)) utvidelsesoperatør. Så du kan bruke det i alle POSIX-kompatible skall (sh av alle moderne Unix-likes, dash, bash, yash, mksh, zsh, posh, ksh … ).

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

ksh introduserte også en let som får samme slags aritmetiske uttrykk, utvider seg ikke til noe, men returnerer en exit-status basert på om uttrykket resolv es til 0 eller ikke, som i expr:

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

Som sitatet gjør det imidlertid vanskelig og ikke veldig leselig (ikke i samme grad som expr selvfølgelig), ksh introduserte også en ((...)) alternativ form:

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

som er mye mer leselig og bør brukes i stedet.

let og ((...)) er bare tilgjengelige i ksh, zsh og bash.$((...)) syntaksen bør foretrekkes hvis det er behov for bærbarhet til andre skall, expr er bare nødvendig for pre-POSIX Bourne-lignende skjell (vanligvis Bourne-skallet eller tidlige versjoner av Almquist-skallet).

På ikke-Bourne-fronten er det noen skall med innebygd aritmetisk operator:

  • csh / tcsh (faktisk det første Unix-skallet med aritmetisk evaluering innebygd):

    @ a = 3 * (2 + 1) 
  • akanga (basert på rc)

    a = $:"3 * (2 + 1)" 
  • som en historikknotat, hadde den originale versjonen av Almquist-skallet, som ble lagt ut på usenet i 1989, en expr innebygd (faktisk slått sammen med test), men den ble fjernet senere.

Kommentarer

  • Jeg lærer noe nytt hver dag av deg, St é phane. Jeg setter stor pris på POSIX-skallkunnskapen din!
  • Hva med : $((a = a*2))?
  • Hva om jeg har et flytende punkt? Mitt uttrykk er a = $ ((-14 + 0,2 * (1 + 2 + 3))). Feiltokenet er » .2 * (1 + 2 + 3) »
  • @Blaise, så du ‘ d trenger et skall som støtter flytende punkter i $((...)) som zsh, ksh93 eller yash.

Svar

expr er en ekstern kommando, det er ikke spesiell skallsyntaks. Derfor, hvis du vil at expr skal se skallets spesialtegn, må du beskytte dem mot parsing av skallet ved å sitere dem. Videre trenger expr at hvert nummer og operatør skal sendes som en egen parameter. Dermed:

expr 3 \* \( 2 + 1 \) 

Med mindre du jobber med et antikt unix-system fra 1970- eller 1980-tallet, er det veldig liten grunn til å bruke expr. I gamle dager hadde skjell ikke en innebygd måte å utføre regning på, og du måtte i stedet ringe expr. Alle POSIX-skjell har innebygd aritmetikk via aritmetisk utvidelse syntaksen.

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

The konstruere $((…)) utvides til resultatet av det aritmetiske uttrykket (skrevet i desimal). Bash støtter, som de fleste skjell, bare heltall aritmetisk modulo 2 64 (eller modulo 2 32 for eldre versjoner av bash og noen andre skall på 32-bit maskiner).

Bash tilbyr en ekstra praktisk syntaks når du vil utføre oppgaver eller for å teste om et uttrykk er 0, men bryr seg ikke om resultatet. Denne konstruksjonen eksisterer også i ksh og zsh, men ikke i vanlig sh.

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

I tillegg til heltallsregning, expr tilbyr noen få strengmanipuleringsfunksjoner. Disse er også underordnet av funksjonene til POSIX-skall, bortsett fra en: expr STRING : REGEXP tester om strengen samsvarer med den angitte regexp. Et POSIX-skall kan ikke gjøre dette uten eksterne verktøy, men bash kan med [[ STRING =~ REGEXP ]] (med en annen regexp-syntaks expr er et klassisk verktøy og bruker BRE, bash bruker ERE).

Med mindre du vedlikeholder skript som kjører på 20 år gamle systemer, trenger du ikke vite at expr noen gang har eksistert. Bruk skallaritmetikk.

Kommentarer

  • expr foo : '\(.\)' gjør også tekstutpakking. bash ‘ s BASH_REMATCH oppnår noe lignende. Det gjør også strengesammenligning, noe POSIX [ ikke gjør (selv om man kunne tenke seg måter å bruke sort til det).
  • understrek som plassholder for syntaks — du er en Schemer, @Giles? :]
  • @ RubyTuesdayDONO Jeg brukte ikke ‘ ikke en understreking her. Feilleser du U + 2026 HORISONTAL ELLIPSIS? I så fall kan du prøve å bruke en større skrift.
  • @Giles – ok, ja, det ser bare ut som et understrek på grunn av skriftstørrelsen min. for meg er » Schemer » et supplement, og det ‘ er ikke som ellips versus understreking endrer betydningen uansett … ikke nødvendig å bli snarky over det: /

Svar

Bruk parentes med sitater:

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

Sitatene forhindrer bash i å tolke parentesen som bash-syntaks.

Kommentarer

  • Det Nicolas illustrerer, men ikke forklarer, er at symbolene på expr kommandolinjen må være atskilt med mellomrom; så; for eksempel vil expr 3 "*" "(2" "+" "1)" ikke fungere . (BTW, du trenger sannsynligvis ikke å sitere +.)
  • Parentesene er ikke ‘ t nøkkelord som while og [[, de ‘ er syntaksen. Hvis de var nøkkelord, ville de ikke ‘ tolkes slik i kommandoargumenter. Du trenger anførselstegn slik at bash ikke ‘ ikke analyserer dem, men i stedet ser en streng bokstavelig.

Svar

Hvis du har bc ..

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

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *