In shell-script kunnen we expr $a*$b
vervangen door $(($a+$b))
.
Maar waarom niet alleen met (($a+$b))
, want in elke bron staat geschreven dat (())
bedoeld is voor de berekening van gehele getallen.
Dus we gebruiken $(())
als er variabelen zijn in plaats van gehele getallen, nietwaar? En wat moeten we gebruiken in plaats van $(())
wanneer variabelen zwevende waarden kunnen ontvangen?
Opmerkingen
- Zie ook unix.stackexchange.com/questions/149823/…
Antwoord
-
Voor rekenkunde is
expr
archaïsch. Gebruik het niet. * -
$((...))
en((...))
lijken erg op elkaar. Beide doen alleen berekeningen met gehele getallen. Het verschil is dat$((...))
het resultaat van de berekening retourneert en((...))
niet. Dus$((...))
is handig inecho
statements:$ a=2; b=3; echo $((a*b)) 6
((...))
is handig als u een variabele wilt toewijzen of een afsluitcode wilt instellen:$ a=3; b=3; ((a==b)) && echo yes yes
-
Als u zwevend wilt puntberekeningen, gebruik
bc
ofawk
:$ echo "4.7/3.14" | bc -l 1.49681528662420382165 $ awk "BEGIN{print 4.7/3.14}" 1.49682
* Even terzijde: expr
blijft handig voor het afhandelen van tekenreeksen wanneer klodders niet goed genoeg zijn en een POSIX-methode nodig is om reguliere expressies af te handelen.
Opmerkingen
- Als expr archaïsch is, wat moeten we dan gebruiken in plaats van expr-tekst: '. * '
- Als
s
een shellvariabele is, is de lengte${#s}
- $ {#} betekent een aantal argumenten en $ (# s} betekent een aantal karakters van een variabele?
- Ja. Dat ' klopt.
- @Stranger Veel gebruik van
expr STRING : REGEX
kan worden geschreven alscase STRING in PATTERN)
.expr
is alleen nuttig als REGEX ' niet kan worden uitgedrukt met shell-jokertekens.
Answer
expr is oud, maar het heeft een beperkt nut dat ik kan bedenken. Stel dat u in een string wilt zoeken. Als je POSIX met grep wilt blijven, moet je een pipe gebruiken:
if echo november | grep nov then : do something fi
expr kan dit doen zonder een pipe:
if expr november : nov then : do something fi
de enige catch is expr werkt met verankerde strings, dus als je wilt matchen na het begin, moet je de REGEXP wijzigen:
if expr november : ".*ber" then : do something fi
Met betrekking tot (( ))
, deze constructie is niet POSIX , dus moet worden vermeden.
Met betrekking tot $(( ))
hoeft u het dollarteken niet op te nemen:
$ fo=1 $ go=2 $ echo $((fo + go)) 3
Opmerkingen
- Veel gebruik van
expr STRING : REGEX
kan worden geschreven alscase STRING in PATTERN)
.expr
is alleen nuttig als REGEX ' niet kan worden uitgedrukt met shell-jokertekens.
Answer
Het lijkt erop dat de volgende programmas min of meer hetzelfde doen en niet echt verschillen. Maar dat is niet waar.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=$((s+1)) echo $s
Dit is de juiste manier om dit te implementeren. De uitdrukking s + 1 wordt geëvalueerd door de shell en kan worden toegewezen aan een variabele.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=`expr $s+1` echo $s
Hier zal de uitdrukking worden berekend door het programma expr, dat” geen shell is ingebouwd, maar een extern Unix-programma. Dus in plaats van simpelweg 1 en s toe te voegen, moet een programma worden gestart en moet de uitvoer ervan worden gelezen en naar de variabele worden geschreven. Het starten van een programma vergt veel middelen en veel tijd. En dit programma wordt 1000000 keer uitgevoerd. Het programma zal dus veel langzamer zijn dan het vorige. Desalniettemin werkt de code correct.
#!/bin/bash -e s=-1000 for (( i=0; i<1000000; i++ )), do ((s=s+1)) echo $s
Als de vlag -e niet is ingesteld, zal het programma ook correct werken. Maar als -e is ingesteld wanneer s = -1 en ((s = s + 1)) wordt berekend. De uitdrukking s = s + 1 resulteert in 0 en de afsluitcode van ((0)) is> 0, wat door de shell wordt geïnterpreteerd als een fout en de shell verlaat het programma.
De reden om de vlag -e in te stellen is dat dit de eenvoudigste manier is om fouten te verwerken: stop als er een fout optreedt.