I shell-skript kan vi erstatte expr $a*$b
med $(($a+$b))
.
Men hvorfor ikke bare med (($a+$b))
, for i en hvilken som helst ressurs står det at (())
er for heltallsberegning.
Så vi bruker $(())
når det er variabler i stedet for heltalsverdier, gjør vi? Og hva skal vi bruke i stedet for $(())
når variabler kan motta flyteverdier?
Kommentarer
- Se også unix.stackexchange.com/questions/149823/…
Svar
-
For regning er
expr
arkaisk. Ikke bruk den. * -
$((...))
og((...))
er veldig like. Begge gjør bare heltallberegninger. Forskjellen er at$((...))
returnerer resultatet av beregningen og((...))
ikke. Dermed$((...))
er nyttig iecho
utsagn:$ a=2; b=3; echo $((a*b)) 6
((...))
er nyttig når du vil tilordne en variabel eller angi en utgangskode:$ a=3; b=3; ((a==b)) && echo yes yes
-
Hvis du vil flyte punktberegninger, bruk
bc
ellerawk
:$ echo "4.7/3.14" | bc -l 1.49681528662420382165 $ awk "BEGIN{print 4.7/3.14}" 1.49682
* Som en side, forblir expr
nyttig for strenghåndtering når globs ikke er gode nok og en POSIX-metode er nødvendig for å håndtere vanlige uttrykk.
Kommentarer
- Hvis expr er arkaisk, hva skal vi bruke i stedet for expr text: '. * '
- Hvis
s
er en skallvariabel, er dens lengde${#s}
- $ {#} betyr et antall argumenter og $ (# s} betyr at antall tegn i en variabel gjør det?
- Ja. At ' er riktig.
- @Stranger Mange bruksområder for
expr STRING : REGEX
kan skrives somcase STRING in PATTERN)
.expr
er bare nyttig når REGEX kan ' t uttrykkes med jokertegn fra skall.
Svar
expr er gammel, men det har en begrenset bruk jeg kan tenke meg. Si at du vil søke i en streng. Hvis du vil være POSIX med grep, må du bruke et rør:
if echo november | grep nov then : do something fi
expr kan gjøre dette uten et rør:
if expr november : nov then : do something fi
den eneste fangsten er ekspr fungerer med forankrede strenger, så hvis du vil matche etter begynnelsen, må du endre REGEXP:
if expr november : ".*ber" then : do something fi
Når det gjelder (( ))
, er denne konstruksjonen ikke POSIX , så det bør unngås.
Når det gjelder $(( ))
, trenger du ikke å ta med dollartegnet:
$ fo=1 $ go=2 $ echo $((fo + go)) 3
Kommentarer
- Mange bruksområder av
expr STRING : REGEX
kan skrives somcase STRING in PATTERN)
.expr
er bare nyttig når REGEX kan ' t uttrykkes med jokertegn fra skall.
Svar
Det ser ut til at følgende programmer gjør mer eller mindre det samme, og de skiller seg ikke veldig ut. Men det er ikke sant.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=$((s+1)) echo $s
Dette er den riktige måten å implementere dette på. Uttrykket s + 1 blir evaluert av skallet og kan tilordnes en variabel.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=`expr $s+1` echo $s
Her vil uttrykket bli beregnet av programmet expr, som ikke er et shell-innebygd men et eksternt Unix-program. Så i stedet for å bare legge til 1 og s, må et program startes og utgangen må leses og skrives til variabelen. Å starte et program trenger mye ressurser og mye tid. Og dette programmet kjøres 1000000 ganger. Så programmet vil være mye tregere enn det forrige. Likevel fungerer koden riktig.
#!/bin/bash -e s=-1000 for (( i=0; i<1000000; i++ )), do ((s=s+1)) echo $s
Hvis -e-flagget ikke er angitt, vil programmet også fungere riktig. Men hvis -e er satt når s = -1 og ((s = s + 1)) beregnes. Uttrykket s = s + 1 evalueres til 0 og utgangskoden til ((0)) er> 0 som tolkes som en feil av skallet og skallet går ut av programmet.
Årsaken til å sette flagget -e er at det er den enkleste måten å behandle feil på: stopp hvis en feil oppstår.