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
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 medtest
), 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
‘ sBASH_REMATCH
oppnår noe lignende. Det gjør også strengesammenligning, noe POSIX[
ikke gjør (selv om man kunne tenke seg måter å brukesort
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 vilexpr 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
let
. Det ‘ er ikke noe mer standard eller bærbart enn(( a = 3 * (2 + 1) ))
(begge kommer fraksh
og er bare tilgjengelig i ksh, bash og zsh) og det ‘ er mindre leselig eller lett å sitere. Bruka=$((3 * (2 + 1)))
for å være bærbar.((a = 3 * (2 + 1) ))
, en for bærbarheta=$((3 * (2 + 1)))
), så det ‘ er ikke et notat mot deg eller ditt svar, men mot at det er valgt svar og toppscorer .a=1 $[a+2]
ellera=1 b=2 $[a+b]
. Er deres grunn til å unngå denne syntaksen?