expr
synes ikke at kunne lide parentes (brugt i matematik til eksplicit operatørprioritet):
expr 3 * (2 + 1) bash: syntax error near unexpected token `("
Hvordan udtrykkes operatørprioritet i bash?
Svar
En anden måde at bruge let
bash builtin:
$ let a="3 * (2 + 1)" $ printf "%s\n" "$a" 9
Bemærk
Som @ Stéphane Chazelas påpegede , i bash
skal du bruge ((...))
til at regne over expr
eller let
for læsbarhed.
For bærbarhed skal du bruge $((...))
ligesom @Bernhard svar .
Kommentarer
Svar
Du kan bruge den aritmetiske udvidelse i stedet.
echo "$(( 3 * ( 2 + 1 ) ))" 9
Efter min personlige mening ser det lidt pænere ud end at bruge expr
.
Fra man bash
Aritmetisk udvidelse Aritmetisk udvidelse tillader evaluering af et aritmetisk udtryk og erstatning af resultatet. Formatet for aritmetisk udvidelse er:
$((expression))
Udtrykket behandles som om det var inden for dobbelt anførselstegn, men et dobbelt citat inden for parenteserne behandles ikke specielt. Alle tokens i udtrykket gennemgår parameterudvidelse, strengudvidelse, kommandosubstitution og fjernelse af tilbud. Aritmetiske udvidelser kan være indlejrede.
Evalueringen udføres i overensstemmelse med nedenstående regler under ARITMETISK EVALUERING. Hvis udtrykket er ugyldigt, udskriver bash en meddelelse, der angiver fiasko, og der forekommer ingen erstatning.
Kommentarer
- Bortset fra læsbarhed, kræver det ikke ‘ at det forkerer en ekstra proces for at gøre aritmetikken; det ‘ håndteres af selve skallen.
- Bemærk at i POSIX-skaller er det ‘ underlagt ordet splittelse, så det er ‘ en god vane at citere det i listesammenhænge.
- Når jeg prøver dette på bash shell får jeg ‘ Ulovligt variabelnavn. ”
Svar
Der er ingen grund til at bruge expr
til aritmetik i moderne skaller.
POSIX definerer $((...))
udvidelsesoperatør. Så du kan bruge det i alle POSIX-kompatible skaller (sh
af alle moderne Unix-lignende, dash, bash, yash, mksh, zsh, posh, ksh … ).
a=$(( 3 * (2 + 1) )) a=$((3*(2+1)))
ksh
introducerede også en let
indbygget får den samme slags aritmetiske udtryk, udvider sig ikke til noget, men returnerer en exitstatus baseret på, hvorvidt udtrykket resolv es til 0 eller ej, som i expr
:
if let "a = 3 * (2 + 1)"; then echo "$a is non-zero" fi
Da citatet imidlertid gør det akavet og ikke meget læselig (ikke i samme omfang som expr
selvfølgelig), ksh
introducerede 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 meget mere læselig og skal bruges i stedet.
let
og ((...))
er kun tilgængelige i ksh
, zsh
og bash
.$((...))
syntaksen bør foretrækkes, hvis der er behov for bærbarhed til andre skaller, expr
er kun nødvendig til pre-POSIX Bourne-lignende skaller (typisk Bourne-skallen eller tidlige versioner af Almquist-skallen).
På den ikke-Bourne front er der et par skaller med indbygget aritmetisk operator:
-
csh
/tcsh
(faktisk den første Unix-skal med aritmetisk evaluering indbygget):@ a = 3 * (2 + 1)
-
akanga
(baseret pårc
)a = $:"3 * (2 + 1)"
-
som en historienote, havde den originale version af Almquist-skallen, som den blev offentliggjort på usenet i 1989, en
expr
builtin (faktisk flettet medtest
), men det blev fjernet senere.
Kommentarer
- Jeg lærer noget nyt hver dag af dig, St é phane. Jeg sætter stor pris på din POSIX-shell-viden!
- Hvad med
: $((a = a*2))
? - Hvad hvis jeg har et flydende punkt? Mit udtryk er a = $ ((-14 + 0,2 * (1 + 2 + 3))). Fejltokenet er ” .2 * (1 + 2 + 3) ”
- @Blaise, så skal du ‘ d har brug for en skal, der understøtter flydende punkter i
$((...))
som zsh, ksh93 eller yash.
Svar
expr
er en ekstern kommando, det er ikke særlig shell-syntaks. Derfor, hvis du vil have expr
til at se shell-specialtegn, skal du beskytte dem mod parsing af shell ved at citere dem. Desuden skal expr
hvert nummer og operatør sendes som en separat parameter. Således:
expr 3 \* \( 2 + 1 \)
Medmindre du arbejder på et antikt unix-system fra 1970erne eller 1980erne, er der meget ringe grund til at bruge expr
. I gamle dage havde skaller ikke en indbygget måde at udføre aritmetik på, og du var nødt til at kalde expr
i stedet. Alle POSIX-skaller har indbygget aritmetik via aritmetisk udvidelse syntaks.
echo "$((3 * (2 + 1)))"
konstruktion $((…))
udvides til resultatet af det aritmetiske udtryk (skrevet i decimal). Bash understøtter, som de fleste skaller, kun heltal aritmetisk modulo 2 64 (eller modulo 2 32 til ældre versioner af bash og nogle andre skaller på 32-bit maskiner).
Bash tilbyder en yderligere bekvemmelighedssyntaks , når du vil udføre opgaver eller for at teste, om et udtryk er 0, men er ligeglad med resultatet. Denne konstruktion findes også i ksh og zsh, men ikke i almindelig sh.
((x = 3 * (2+1))) echo "$x" if ((x > 3)); then …
Udover heltal aritmetik, expr
tilbyder nogle få strengmanipulationsfunktioner. Disse underordnes også af funktioner i POSIX-skaller, bortset fra en: expr STRING : REGEXP
tester, om strengen matcher den angivne regexp. En POSIX-shell kan ikke gøre dette uden eksterne værktøjer, men bash kan med [[ STRING =~ REGEXP ]]
(med en anden regexp-syntaks – expr
er et klassisk værktøj og bruger BRE, bash bruger ERE).
Medmindre du vedligeholder scripts der kører på 20 år gamle systemer, behøver du ikke vide, at expr
nogensinde har eksisteret. Brug shell-aritmetik.
Kommentarer
-
expr foo : '\(.\)'
udfører også tekstudtrækning.bash
‘ sBASH_REMATCH
opnår noget lignende. Det gør også strengesammenligning, hvilket POSIX[
ikke gør (selvom man kunne forestille sig måder at brugesort
til det). - understreg som pladsholder for syntaks — er du en Schemer, @Giles? :]
- @ RubyTuesdayDONO Jeg brugte ikke ‘ ikke en understregning her. Læser du forkert U + 2026 HORIZONTAL ELLIPSIS? Hvis det er tilfældet, så prøv at bruge en større skrifttype.
- @Giles – okay, ja, det ser kun ud som en understregning på grund af min skriftstørrelse. for mig er ” Schemer ” et supplement, og det ‘ er ikke som ellipsis versus understregning ændrer betydningen alligevel … ikke nødvendigt at blive snarky over det: /
Svar
Brug parentes med citater:
expr 3 "*" "(" 2 "+" 1 ")" 9
Citaterne forhindrer bash i at tolke parentesen som bash-syntaks.
Kommentarer
- Hvad Nicolas illustrerer, men ikke forklarer, er, at tokens på kommandolinjen
expr
skal adskilles med mellemrum; så; for eksempelexpr 3 "*" "(2" "+" "1)"
fungerer ikke . (Også BTW, du behøver sandsynligvis ikke citere+
.) - Parenteserne er ‘ t nøgleord som
while
og[[
, de ‘ er syntaks. Hvis de var nøgleord, ville de ikke ‘ ikke fortolkes som sådan i kommandoargumenter. Du har brug for anførselstegn, så bash ikke ‘ ikke analyserer dem, men i stedet ser en streng bogstavelig.
Svar
Hvis du har bc ..
echo "3 * (2 + 1)"|bc 9
let
. Det ‘ er ikke mere standard eller bærbart end(( a = 3 * (2 + 1) ))
(begge kommer fraksh
og er kun tilgængelige i ksh, bash og zsh) og det ‘ er mindre læseligt eller let at citere. Bruga=$((3 * (2 + 1)))
til at være bærbar.((a = 3 * (2 + 1) ))
, en til bærbarheda=$((3 * (2 + 1)))
), så det ‘ er ikke en note imod dig eller dit svar, men mod at det er det valgte svar og topscorer .a=1 $[a+2]
ellera=1 b=2 $[a+b]
. Er deres grund til at undgå denne syntaks?