Parentes i expr-aritmetik: 3 * (2 + 1)

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

  • +1 Endnu mere læselig! Jeg sendte mit spørgsmål + svar og tænkte bare, at det ville være nyttigt for mine Linux-brugere, men nu får jeg en masse fordel af de andre svar 🙂
  • Der ‘ er ingen grund til at bruge let. Det ‘ er ikke mere standard eller bærbart end (( a = 3 * (2 + 1) )) (begge kommer fra ksh og er kun tilgængelige i ksh, bash og zsh) og det ‘ er mindre læseligt eller let at citere. Brug a=$((3 * (2 + 1))) til at være bærbar.
  • Jeg ‘ siger ikke det ‘ er forkert, jeg ‘ jeg siger bare, det skal ikke bruges, da der er bedre alternativer (en for læsbarhed ((a = 3 * (2 + 1) )), en til bærbarhed a=$((3 * (2 + 1)))), så det ‘ er ikke en note imod dig eller dit svar, men mod at det er det valgte svar og topscorer .
  • @St é phaneChazelas: Opdateret mit svar!
  • Jeg har altid brugt a=1 $[a+2] eller a=1 b=2 $[a+b]. Er deres grund til at undgå denne syntaks?

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 med test), 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 ‘ s BASH_REMATCH opnår noget lignende. Det gør også strengesammenligning, hvilket POSIX [ ikke gør (selvom man kunne forestille sig måder at bruge sort 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 eksempel expr 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 

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *