Med hjälp av expr, $ (()), (())

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

Svar

  1. För aritmetik är expr arkaiskt. Använd det inte. *

  2. $((...)) 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 i echo 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 
  3. Om du vill flyta punktberäkningar, använd bc eller awk:

    $ 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 som case 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 som case 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.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *