I shell-script kan vi erstatte expr $a*$b
med $(($a+$b))
.
Men hvorfor ikke bare med (($a+$b))
, for i en hvilken som helst ressource står det, at (())
er beregnet til helberegning.
Så vi bruger $(())
når der er variabler i stedet for heltal værdier gør vi? Og hvad skal vi bruge i stedet for $(())
når variabler kan modtage float-værdier?
Kommentarer
- Se også unix.stackexchange.com/questions/149823/…
Svar
-
For aritmetik er
expr
arkaisk. Brug det ikke. * -
$((...))
og((...))
er meget ens. Begge foretager kun heltalberegninger. Forskellen er, at$((...))
returnerer resultatet af beregningen, og((...))
ikke. Således$((...))
er nyttigt iecho
udsagn:$ a=2; b=3; echo $((a*b)) 6
((...))
er nyttigt, når du vil tildele en variabel eller indstille en udgangskode:$ a=3; b=3; ((a==b)) && echo yes yes
-
Hvis du vil flyde punktberegninger, brug
bc
ellerawk
:$ echo "4.7/3.14" | bc -l 1.49681528662420382165 $ awk "BEGIN{print 4.7/3.14}" 1.49682
* Som en sidebemærkning forbliver expr
nyttig til strenghåndtering, når globs ikke er gode nok, og en POSIX-metode er nødvendig for at håndtere regulære udtryk.
Kommentarer
- Hvis expr er arkaisk, hvad skal vi bruge i stedet for expr-tekst: '. * '
- Hvis
s
er en skalvariabel, er dens længde${#s}
- $ {#} betyder et antal argumenter, og $ (# s} betyder, at et antal tegn i en variabel gør det?
- Ja. At ' er rigtigt.
- @Stranger Mange anvendelser af
expr STRING : REGEX
kan skrives somcase STRING in PATTERN)
.expr
er kun nyttigt, når REGEX kan ' t udtrykkes med shell-jokertegn.
Svar
expr er gammel, men det har en begrænset anvendelse, jeg kan tænke på. Sig, at du vil søge i en streng. Hvis du vil forblive POSIX med grep, skal du bruge et rør:
if echo november | grep nov then : do something fi
expr kan gøre dette uden et rør:
if expr november : nov then : do something fi
den eneste fangst er expr fungerer med forankrede strenge, så hvis du vil matche efter starten, skal du ændre REGEXP:
if expr november : ".*ber" then : do something fi
Med hensyn til (( ))
er denne konstruktion ikke POSIX , så det bør undgås.
Med hensyn til $(( ))
behøver du ikke medtage dollartegnet:
$ fo=1 $ go=2 $ echo $((fo + go)) 3
Kommentarer
- Mange anvendelser af
expr STRING : REGEX
kan skrives somcase STRING in PATTERN)
.expr
er kun nyttigt, når REGEX kan ' t udtrykkes med shell-jokertegn.
Svar
Det ser ud til, at de følgende programmer gør mere eller mindre det samme, og de adskiller sig ikke rigtig. Men det er ikke sandt.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=$((s+1)) echo $s
Dette er den rigtige måde at implementere dette på. Udtrykket s + 1 evalueres af skallen og kan tildeles en variabel.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=`expr $s+1` echo $s
Her beregnes udtrykket af programmet expr, som ikke er en shell-indbygget men et eksternt Unix-program. Så i stedet for blot at tilføje 1 og s, skal et program startes, og dets output skal læses og skrives til variablen. At starte et program har brug for mange ressourcer og meget tid. Og dette program køres 1000000 gange. Så programmet vil være meget langsommere end det foregående. Ikke desto mindre fungerer koden korrekt.
#!/bin/bash -e s=-1000 for (( i=0; i<1000000; i++ )), do ((s=s+1)) echo $s
Hvis -e-flag ikke er indstillet, fungerer programmet også korrekt. Men hvis -e er indstillet når s = -1 og ((s = s + 1)) beregnes. Udtrykket s = s + 1 evalueres til 0, og udgangskoden for ((0)) er> 0, som fortolkes som en fejl af skallen og skallen forlader programmet.
Årsagen til at indstille flaget -e er, at det er den enkleste måde at behandle fejl på: stop, hvis der opstår en fejl.