I skalskriptet kan vi ersätta expr $a*$b
med $(($a+$b))
.
Men varför inte bara med (($a+$b))
, för i någon resurs står det att (())
är för heltalsberäkning.
Så vi använder $(())
när det finns variabler istället för heltalvärden, eller hur? Och vad ska vi använda istället för $(())
när variabler kan ta emot flytvärden?
Kommentarer
- Se även unix.stackexchange.com/questions/149823/…
Svar
-
För aritmetik är
expr
arkaiskt. Använd det inte. * -
$((...))
och((...))
är mycket lika. Båda gör bara heltalsberäkningar. Skillnaden är att$((...))
returnerar resultatet av beräkningen och((...))
inte. Således$((...))
är användbart iecho
uttalanden:$ a=2; b=3; echo $((a*b)) 6
((...))
är användbart när du vill tilldela en variabel eller ställa in en utgångskod:$ a=3; b=3; ((a==b)) && echo yes yes
-
Om du vill flyta punktberäkningar, använd
bc
ellerawk
:$ echo "4.7/3.14" | bc -l 1.49681528662420382165 $ awk "BEGIN{print 4.7/3.14}" 1.49682
* Som bortfall är expr
fortfarande användbart för stränghantering när globs inte är tillräckligt bra och en POSIX-metod behövs för att hantera reguljära uttryck.
Kommentarer
- Om expr är arkaiskt, vad ska vi använda istället för expr text: '. * '
- Om
s
är en skalvariabel, är dess längd${#s}
- $ {#} betyder ett antal argument och $ (# s} betyder att ett antal tecken i en variabel gör det?
- Ja. Att ' är rätt.
- @Stranger Många användningsområden för
expr STRING : REGEX
kan skrivas somcase STRING in PATTERN)
.expr
är bara användbart när REGEX kan ' t uttryckas med skal-jokertecken.
Svar
expr är gammalt, men det har en begränsad användning jag kan tänka mig. Säg att du vill söka i en sträng. Om du vill vara POSIX med grep måste du använda ett rör:
if echo november | grep nov then : do something fi
expr kan göra detta utan ett rör:
if expr november : nov then : do something fi
den enda fångsten är expr fungerar med förankrade strängar, så om du vill matcha efter början måste du ändra REGEXP:
if expr november : ".*ber" then : do something fi
När det gäller (( ))
är denna konstruktion inte POSIX , så det bör undvikas.
När det gäller $(( ))
behöver du inte ta med dollartecknet:
$ fo=1 $ go=2 $ echo $((fo + go)) 3
Kommentarer
- Många användningsområden av
expr STRING : REGEX
kan skrivas somcase STRING in PATTERN)
.expr
är bara användbart när REGEX kan ' t uttryckas med skal-jokertecken.
Svar
Det verkar som om följande program gör ungefär samma och de skiljer sig inte riktigt åt. Men det är inte sant.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=$((s+1)) echo $s
Detta är rätt sätt att implementera detta. Uttrycket s + 1 utvärderas av skalet och kan tilldelas en variabel.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=`expr $s+1` echo $s
Här beräknas uttrycket av programmet expr, vilket inte är ett inbyggt skal men ett externt Unix-program. Så istället för att helt enkelt lägga till 1 och s måste ett program startas och dess utdata måste läsas och skrivas till variabeln. Att starta ett program kräver mycket resurser och mycket tid. Och det här programmet körs 1000000 gånger. Så programmet blir mycket långsammare än det föregående. Ändå fungerar koden korrekt.
#!/bin/bash -e s=-1000 for (( i=0; i<1000000; i++ )), do ((s=s+1)) echo $s
Om -e-flaggan inte är inställd fungerar programmet också korrekt. Men om -e är inställt när s = -1 och ((s = s + 1)) beräknas. Uttrycket s = s + 1 utvärderas till 0 och utgångskoden för ((0)) är> 0 vilket tolkas som ett fel av skalet och skalet lämnar programmet.
Anledningen till att ställa in flaggan -e är att det är det enklaste sättet att bearbeta fel: stoppa om ett fel uppstår.