Die bash bietet eine Reihe leistungsfähiger Möglichkeiten, Werte von Parametern, Variablen etc zu ersetzen. Da die Syntax oftmals recht kryptisch ist und in anderen Programmiersprachen so nicht vorkommt, wird die Substitution von vielen nicht verwendet. Das ist ein Fehler, denn gerade die Substitution ist sehr leistungsfähig und erhöht die Performance von Shellscripten. Bevor die bash eine Kommandozeile ausführt, sucht sie nach Anweisungen zur Substitution und führt diese noch vor der Ausführung des eigentlichen Kommandos durch. Um den Umfang etwas einzuschränken, möchte ich hier nur einige Möglichkeiten der Substitution/Expansion zeigen.
Die Parameterexpansion bietet die Möglichkeit, den Wert eines Parameters oder einer Variable in ein Kommando einzufügen und ggf zu modifizieren.
#!/bin/bash TOP=13 TOPWERT=10 echo $TOP echo "$TOP" echo "$TOPWERT" echo "${TOP}WERT" echo "${TOPWERT}" |
bash-2.05b$ ./test 13 13 10 13WERT 10 bash-2.05b$ |
#!/bin/bash DATEINAME="test datei" rm ${DATEINAME} |
#!/bin/bash DATEINAME="test datei" rm "${DATEINAME}" |
#!/bin/bash TEST="" VAR="ein test" DATEI=/var/log/messages echo "1. >>${VAR}<<" echo "2. >>${PETER:-12}<< und der Inhalt von PETER >>${PETER}<<" echo "3. >>${VAR:-10}<<" echo "4. >>${PETER:=12}<< und der Inhalt von PETER >>${PETER}<<" echo "5. HANS>>${HANS:+test}<< TEST>>${TEST:+test}<< VAR>>${VAR:+test}<<" echo "6. >>${DATEI:4}<< und >>${DATEI:4:6}<<" echo "7. DATEI enthaelt >>${#DATEI}<< Zeichen" echo "8. DATEINAME ist >>${DATEI##*/}<<" echo "9. PFADNAME ist >>${DATEI%/*}<<" echo "10. >>${DATEI//e/a}<<" echo "11. ${HANS:?Variable HANS existiert nicht}" |
bash-2.05b$ ./test 1. >>ein test<< 2. >>12<< und der Inhalt von PETER >><< 3. >>ein test<< 4. >>12<< und der Inhalt von PETER >>12<< 5. HANS>><< TEST>><< VAR>>test<< 6. >>/log/messages<< und >>/log/m<< 7. DATEI enthaelt >>17<< Zeichen 8. DATEINAME ist >>messages<< 9. PFADNAME ist >>/var/log<< 10. >>/var/log/massagas<< ./test: line 16: HANS: Variable HANS existiert nicht bash-2.05b$ |
1.Zeile | Der Inhalt von VAR wird expandiert und durch echo ausgegeben. |
2.Zeile | Da die Variable PETER nicht existiert, wird sie mit dem Wert 12 expandiert, die Variable PETER wird nicht erzeugt! |
3.Zeile | Da die Variable VAR existiert, wird der Inhalt ausgegeben. |
4.Zeile | Da die Variable PETER nicht existiert, wird sie mit dem Wert 12 angelegt und expandiert. |
5.Zeile | Da die Variable HANS nicht existiert, wird sie als NULL-String expandiert, die Variable TEST enthält einen NULL-String und wird als NULL-String expandiert. Die Variable VAR enthält keinen NULL-String und wird als test expandiert. |
6.Zeile | Aus der Variable DATEI wird zuerst alles ab dem 4.Zeichen expandiert und danach nach dem 4.Zeichen die 6 folgenden Zeichen. |
7.Zeile | Die Anzahl der Zeichen in der Variable DATEI wird zurückgegeben. |
8.Zeile | Es wird die größtmögliche Anzahl von Zeichen mit dem Suchmuster */ von links entfernt und das ist der Pfadname. Es wird der Name der Datei zurückgegeben. |
9.Zeile | Es wird die kleinstmögliche Anzahl von Zeichen mit dem Suchmuster /* von rechts entfernt. Es bleibt der Pfadname übrig. |
10.Zeile | Alle Vorkommen des Zeichens e werden durch ein a ersetzt. |
11.Zeile | Da die Variable HANS nicht existiert, wird das Script abgebrochen und eine Fehlermeldung ausgegeben. |
Die Kommandosubstitution kann auf zwei verschiedene Arten aufgerufen werden.
$( kommando optionen parameter)
oder
` kommando optionen parameter`
Ich bevorzuge die Schreibweise $(..), da sie weniger missverständlich ist, da das ` (back-quote) oftmals mit ´ (Acute-Zeichen), ' (einfaches Anführungszeichen) oder " (doppeltes Anführungszeichen) verwechselt wird.
Bei der Kommandosubstitution wird die Substitutionsanweisung $(..) durch die Ausgabe des Kommandos auf STDOUT ersetzt.
Aus der Ausgabe werden dabei alle anderen Trennzeichen außer einem abschließenden <newline> durch Leerzeichen ersetzt.
Zu beachten ist das, da dann nicht mehr eindeutig erkannt werden kann, welche der Ausgabe in einer Zeile erfolgt sind.
Deshalb ist auch
for VAR in $( ls )
do
....
done
und
for VAR in *
do
....
done
nicht das selbe!!!!
Durch die Kommandosubstitution kann man also die Ausgabe von Kommandos wieder in andere Kommandos einfügen oder die Ausgabe in Variablen auffangen.
Leider schweigt sich die man-Page der bash zum Thema "arithmetische Expansion" extrem aus, weshalb ich hier etwas näher auf dieses Thema eingehen will.
Die bash wartet auch hier mit einer Fülle von Möglichkeiten auf, die leider oft nicht genutzt werden.
Alle hier gemachten Aussagen beziehen sich auf bash-Versionen ab 3.05.
Ähnlich dem Kommando let können in der bash auch arithmetische Berechnungen mit ganzen Zahlen durchgeführt werden.
In früheren Versionen der bash (<2.05) wurden diese durch 32bit-Zahlen dargestellt und bewegten sich deshalb im Bereich von -2147483648 bis 2147483647, also von -231 bis 231-1.
Aktuelle Versionen verwenden 64bit Integerzahlen und damit reicht der Wertebereich von -9223372036854775808 bis 9223372036854775807.
Achtung!! Eine Überschreitung dieses Wertebereiches führt nicht zu einer Fehlermeldung und erzeugt unsinnige Ergebnisse! Bei den Zahlen- und Variablenwerten muss es sich um Ganzzahlen handeln, bei auftretenden Dezimalpunkten bricht die Expansion mit einer Fehlermeldung ab!
Die arithmetische Expansion wird durch die Anweisung $(( ...... )) eingeleitet und durch das Ergebnis der Expansion substituiert.
Sie kann also nur in Kommandoparametern benutzt werden und stellt kein eigenständiges Kommando dar.
Möchte man in einem Script also z.B. eine Variable var um 1 erhöhen, dann liefert der Aufruf $((var++)) eine Fehlermeldung.
bash-3.1$ var=1 bash-3.1$ $((var++)) bash: 1: command not found bash-3.1$ |
bash-3.1$ var=1 bash-3.1$ let "var++" bash-3.1$ echo $var 2 bash-3.1$ : $((var++)) bash-3.1$ echo $var 3 bash-3.1$ ((var++)) bash-3.1$ echo $var 4 bash-3.1$ |
Eine kurze Übersicht soll die Funktionsweise der arithmetischen Expansion der bash verdeutlichen.
Wichtig dabei ist, dass es sich hierbei zum einen um eine reine Expansion handeln kann, dass aber auch Wertzuweisungen an Variablen vorgenommen werden können.
Ein einfaches Additionsbeispiel soll dies verdeutlichen.
Gegeben sind drei Variablen OP1, OP2 und SUM, mit denen verschiedene Operationen durchgeführt werden sollen.
#!/bin/bash OP1=10 OP2=5 SUM=0 echo "$((OP1))" echo "$((OP1+1))" echo "${OP1}" echo "$((OP1+OP2))" echo "${OP1}" echo "${OP2}" echo "$((OP1+OP2+7))" echo "${OP1}" echo "${OP2}" echo "$((SUM=OP1+OP2+7))" echo "${OP1}" echo "${OP2}" echo "${SUM}" echo "$((OP1++))" echo "${OP1}" echo "$((++OP1))" echo "${OP1}" |
bash-3.1$ ./tester 10 11 10 15 10 5 22 10 5 22 10 5 22 10 11 12 12 bash-3.1$ |
Scriptcode | Ausgabe | Erläuterungen |
#!/bin/bash | ||
OP1=10 | Der Variable OP1 wird der Wert 10 zugeordnet. | |
OP2=5 | Der Variable OP2 wird der Wert 5 zugeordnet. | |
SUM=0 | Der Variable SUM wird der Wert 0 zugeordnet um sie zu deklarieren. | |
echo "$((OP1))" | 10 | Es wird keine Rechenoperation ausgeführt, deshalb wird nur einfach der Wert der Variablen OP1 expandiert. |
echo "$((OP1+1))" | 11 | Als Expansion wird die Summe aus dem Wert der Variablen OP1 und 1 zurückgegeben. |
echo "${OP1}" | 10 | Durch die vorhergehende Expansion wurde der Wert der Variablen OP1 jedoch nicht geändert. |
echo "$((OP1+OP2))" | 15 | Als Expansion wird die Summe aus den Werten der Variablen OP1 und OP2 zurückgegeben. |
echo "${OP1}" | 10 | Durch die vorhergehende Expansion bleiben die Variablen OP1 und OP2 ebenfalls unverändert! |
echo "${OP2}" | 5 | |
echo "$((OP1+OP2+7))" | 22 | Als Expansion wird die Summe aus den Werten der Variablen OP1, OP2 und der Zahl 7 zurückgegeben. |
echo "${OP1}" | 10 | Auch durch diese Expansion bleiben die Variablen OP1 und OP2 unverändert! |
echo "${OP2}" | 5 | |
echo "$((SUM=OP1+OP2+7))" | 22 | Als Expansion wird die Summe aus den Werten der Variablen OP1, OP2 und der Zahl 7 zurückgegeben. Gleichzeitig findet eine Zuweisung dieses Wertes in die Variable SUM statt. |
echo "${OP1}" | 10 | Nach wie vor bleiben die Variablen OP1 und OP2 unverändert. |
echo "${OP2}" | 5 | |
echo "${SUM}" | 22 | Durch die Zuweisung wurde jedoch der Wert der Variable SUM mit dem Ergebnis der Expansion belegt! |
echo "$((OP1++))" | 10 | Hierbei handelt es sich um ein Increment in Past-Notation. Es wird der aktuelle Wert der Variable OP1 expandiert und danach um 1 erhöt. |
echo "${OP1}" | 11 | Der neue Wert der Variable OP1 beträgt jetzt also 11, da er um 1 erhöht wurde. |
echo "$((++OP1))" | 12 | Hierbei handelt es sich um ein Increment in Pre-Notation. Zuerst wird der aktuelle Wert der Variable OP1 um 1 erhöht und danach expandiert. |
echo "${OP1}" | 12 | Der neue Wert ist also 12. |
Die bash kennt eine Reihe von arithmetischen Operationen, die in der folgenden Liste aufgeführt sind. Die Operanden erg und op stehen dabei für beliebige Shellvariablen, die Operanden n und m für beliebige Shellvariablen oder Zahlen.
arithmetische Operatoren | ||
Die arithmetischen Operatoren führen vorzeichenbehaftete Ganzzahloperationen aus.
Es ist sicher zu stellen, dass es sich bei den Operanden um gültige Zahlen der vereinbarten Zahlenbasis im gültigen Wertebereich handelt.
Ohne weitere Angabe ist die Zahlenbasis 10 (Dezimalzahlen), sodass die Zahlzeichen 0..9 mit eventuell vorangestelltem Minus - zulässig sind.
Es kann jedoch jeder Zahl eine Zahlenbasis im Bereich von 2..64 vorangestellt werden, die durch den Zahlenwert durch ein # zu trennen ist.
Ber Bereich der zulässigen Zahlzeichen erweitert sich dann um die entsprechende Menge von Buchstaben a, b, c, .... usw. usf.
Die Zahlenbasis ist in jedem Fall dezimal anzugeben! Beispiel: 16#1A für die Hexadezimalzal 1A Die Expansion der Ergebnisse ist in jedem Fall dezimal! |
||
Operation/ Operator | Beispiele | Erläuterung |
Addition + |
$((n+m)) $((erg=n+m)) |
Es wird die Summe aus zwei oder mehreren Summanden (Zahlen und/oder Variablenwerte) berechnet. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
Addition += |
$((erg+=n)) | Es wird der Wert der Variable erg mit dem Wert n addiert und das Ergebnis wieder der Variable erg zugewiesen. Diese Operation stellt also eine verkürzte Schreibweise von $((erg=erg+n)) dar. Der Wert n kann eine Zahl, eine Variable oder ein ganzer Term sein. |
Increment ++ |
$((op++)) $((erg=op++)) $((++op)) $((erg=++op)) |
Der Wert einer Variable op wird um eins erhöht. In der Post-Notation op++ wird der Wert der Variable zuerst expandiert und danach um 1 erhöht. In der Pre-Notation wird der Wert erst um 1 erhöht und danach expandiert. Eine Zuweisung des Ergebnisses der Expansion in eine Shellvariable ist möglich. |
Subtraktion - |
$((n-m)) $((erg=n-m)) |
Es wird die Differenz aus zwei oder mehreren Operanden (Zahlen und/oder Variablenwerte) berechnet. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
Subtraktion -= |
$((erg-=n)) | Es wird vom Wert der Variable erg der Wert n subtrahiert und das Ergebnis wieder der Variable erg zugewiesen. Diese Operation stellt also eine verkürzte Schreibweise von $((erg=erg-n)) dar. Der Wert n kann eine Zahl, eine Variable oder ein ganzer Term sein. |
Decrement -- |
$((op--)) $((erg=op--)) $((--op)) $((erg=--op)) |
Der Wert einer Variable op wird um eins verringert. In der Post-Notation op-- wird der Wert der Variable zuerst expandiert und danach um 1 verringert. In der Pre-Notation wird der Wert erst um 1 verringert und danach expandiert. Eine Zuweisung des Ergebnisses der Expansion in eine Shellvariable ist möglich. |
Multiplikation * |
$((n*m)) $((erg=n*m)) |
Es wird das Produkt aus zwei oder mehreren Faktoren (Zahlen und/oder Variablenwerte) berechnet. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
Multiplikation *= |
$((erg*=n)) | Es wird der Wert der Variable erg mit dem Wert n multipliziert und das Ergebnis wieder der Variable erg zugewiesen. Diese Operation stellt also eine verkürzte Schreibweise von $((erg=erg*n)) dar. Der Wert n kann eine Zahl, eine Variable oder ein ganzer Term sein. |
Potenz ** |
$((n**m)) $((erg=n**m)) |
Es wird die Potenz nm berechnet. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
Division / |
$((n/m)) $((erg=n/m)) |
Es wird eine ganzzahlige Division zweier oder mehrerer Operanden (Zahlen und/oder Variablenwerte) berechnet. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
Division /= |
$((erg/=n)) | Es wird der Wert der Variable erg ganzzahlig durch den Wert n dividiert und das Ergebnis wieder der Variable erg zugewiesen. Diese Operation stellt also eine verkürzte Schreibweise von $((erg=erg/n)) dar. Der Wert n kann eine Zahl, eine Variable oder ein ganzer Term sein. |
Modulo % |
$((n%m)) $((erg=n%m)) |
Es wird eine Modulo-Operation durchgeführt. Babei wird der ganzzahlige Rest der Division zweier Operanden (Zahlen und/oder Variablenwerte) zurückgegeben. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
Modulo %= |
$((erg%=n)) | Es wird der Rest der ganzzahligen Division aus dem Wert der Variable erg und dem Wert n berechnet und das Ergebnis wieder der Variable erg zugewiesen. Diese Operation stellt also eine verkürzte Schreibweise von $((erg=erg%n)) dar. Der Wert n kann eine Zahl, eine Variable oder ein ganzer Term sein. |
bitweise Operatoren | ||
Diese Operatoren beziehen sich auf die binäre Darstellung der Zahlenwerte und führen die logische Verknüpfung zwischen jeweils gleichwertigen Binärstellen der Operanden aus. Bei Verschiebebefehlen wird von rechts eine Null eingeschoben und von links das Vorzeichenbit. | ||
Operation/ Operator | Beispiele | Erläuterung |
bitweises Schieben nach rechts >> |
$((n>>m)) $((erg=n>>m)) |
Der Binärwert n wird bitweise um m Stellen nach rechts geschoben. Die Verschiebung eines Binärwertes um eine Stelle nach rechts entspricht der dezimalen, ganzzahligen Division durch 2 (außer bei -1!!), die Ausführungszeit ist jedoch wesentlich geringer als bei einer Division. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
bitweises Schieben nach rechts >>= |
$((erg>>=m)) | Der Binärwert der Variable erg wird bitweise um m Stellen nach rechts geschoben und das Ergebnis wieder der Variable op zugewiesen. Diese Operation stellt also eine verkürzte Schreibweise von $((erg=erg>>n)) dar. |
bitweises Schieben nach links << |
$((n<<m)) $((erg=n<<m)) |
Der Binärwert n wird bitweise um m Stellen nach links geschoben. Die Verschiebung eines Binärwertes um eine Stelle nach links entspricht der dezimalen Multiplikation mit 2, die Ausf%uuml;hrungszeit ist jedoch wesentlich geringer als bei einer Multiplikation. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
bitweises Schieben nach links <<= |
$((erg<<=m)) | Der Binärwert der Variable erg wird bitweise um m Stellen nach links geschoben und das Ergebnis wieder der Variable op zugewiesen. Diese Operation stellt also eine verkürzte Schreibweise von $((erg=erg<<n)) dar. |
bitweise UND & |
$((n&m)) $((erg=n&m)) |
Die Binärwerte n und m (Zahlen oder Variablenwerte) werden bitweise durch ein logisches UND miteinander verknüpft. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
bitweise UND &= |
$((erg&=n)) | Es wird der Binäwert der Variable erg bitweise durch ein logisches UND mit dem Wert n verknüpft und das Ergebnis wieder der Variable erg zugewiesen. Diese Operation stellt also eine verkürzte Schreibweise von $((erg=erg&n)) dar. Der Wert n kann eine Zahl, eine Variable oder ein ganzer Term sein. |
bitweise ODER ¦ |
$((n¦m)) $((erg=n¦m)) |
Die Binärwerte n und m (Zahlen oder Variablenwerte) werden bitweise durch ein logisches ODER miteinander verknüpft. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
bitweise ODER ¦= |
$((erg¦=n)) | Es wird der Binäwert der Variable erg bitweise durch ein logisches ODER mit dem Wert n verknüpft und das Ergebnis wieder der Variable erg zugewiesen. Diese Operation stellt also eine verkürzte Schreibweise von $((erg=erg¦n)) dar. Der Wert n kann eine Zahl, eine Variable oder ein ganzer Term sein. |
bitweise EXCLUSIV-ODER ^ |
$((n^m)) $((erg=n^m)) |
Die Binärwerte n und m (Zahlen oder Variablenwerte) werden bitweise durch ein logisches EXCLUSIV-ODER miteinander verknüpft. Eine Zuweisung des Ergebnisses in eine Shellvariable ist möglich. |
bitweise EXCLUSIV-ODER ^= |
$((erg^=n)) | Es wird der Binäwert der Variable erg bitweise durch ein logisches EXCLUSIV-ODER mit dem Wert n verknüpft und das Ergebnis wieder der Variable erg zugewiesen. Diese Operation stellt also eine verkürzte Schreibweise von $((erg=erg^n)) dar. Der Wert n kann eine Zahl, eine Variable oder ein ganzer Term sein. |
Vergleichsoperatoren | ||
Die Vergleichsoperatoren dienen dem arithmetischen Vergleich zweier Zahlen, Variablenwerte oder ganzer Terme.
Als Ergebnis der Vergleichsoperation werden nur die beiden boolschen Werte 0 und 1 zurückgegeben.
Bei positivem Ausgang des Vergleichs ist das Ergebnis der Wahrheitswert 1 für wahr (true), bei negativem Ausgang 0 für falsch (false). Achtung!! Wenn Variablen verwendet werden, die unzulässige Zeichen enthalten, dann wird in vielen Fällen eine Fehlermeldung erscheinen. Sollte es sich um Text handeln, so kann es vorkommen, dass dieser mit dem Zahlenwert 0 gleich gesetzt wird, sodass unvorhergesehene Ergebnisse entstehen können! |
||
Operation/ Operator | Beispiele | Erläuterung |
gleich == |
$(( n == m )) | Es wird getestet, ob die Werte n und m gleich sind. |
ungleich != |
$(( n != m )) | Es wird getestet, ob die Werte n und m ungleich sind. |
kleiner als < |
$(( n < m )) | Es wird getestet, ob der Wert n kleiner als der Wert m ist. |
kleiner gleich <= |
$(( n <= m )) | Es wird getestet, ob der Wert n kleiner oder gleich dem Wert m ist. |
größer als > |
$(( n > m )) | Es wird getestet, ob der Wert n größer als der Wert m ist. |
größer gleich >= |
$(( n >= m )) | Es wird getestet, ob der Wert n größer oder gleich dem Wert m ist. |
boolsche Operatoren | ||
Mit diesen Operatoren können die Wahrheitswerte 0 und 1 durch logisches UND, ODER und NICHT verknüpft werden. Als Operanden werden meist Vergleichoperationen eingesetzt, es können aber auch Zahlen oder ganze Termwerte verwendet werden. Alle Werte 0 werden als boolscher Wert 0 (false) interpretiert, alle anderen Zahlenwerte, auch die negativen Zahlen, werden als 1 (wahr) interpretiert. Die boolschen Operatoren sind von den Operanden zwingend durch ein Trennzeichen (space) zu separieren. | ||
Operation/ Operator | Beispiele | Erläuterung |
boolsches UND && |
$(( n && m )) | Es wird der boolsche Wert 1 (wahr) zurückgegeben, wenn n und m nicht 0 (falsch) sind. |
boolsches ODER ¦¦ |
$(( n ¦¦ m )) | Es wird der boolsche Wert 1 (wahr) zurückgegeben, wenn n oder m nicht 0 (falsch) sind oder beide nicht. |
boolsches NICHT ! |
$(( ! n )) | Es wird der boolsche Wert 1 (wahr) zurückgegeben, wenn n gleich 0 (falsch) ist. |
Strukturoperatoren | ||
Die Strukturoperatoren dienen der Erzeugung von Listen und Verzweigungen innerhalb eines arithmetischen Ausdrucks. | ||
ternärer Operator | n ? Liste 1 : Liste2 | Dieser Operator erzeugt eine Verzweigung im Stil einer if ... then ... else ... fi-Anweisung. Wenn der Wert n dem boolschen Wert 1 (true) entspricht, also ungleich Null ist, wird die Liste1 ausgeführt. Ist der Wert n gleich 0 (false), so werden die Anweisungen der Alternativliste Liste2 ausgeführt. |
Listenoperator | Liste1 , Liste2 , ... , ListeN | Sollen innerhalb eines arithmetischen Ausdrucks mehrere Terme berechnet werden, so sind diese durch ein Komma (,) zu trennen. Zuerst werden die Anweisungen der Liste1 ausgeführt, danach die Anweisungender Liste2 usw. usf. und zum Schluß die Anweisungen der ListeN. Expandiert wird dann jeweils nur der Wert des letzten Terms am Ende des ganzen arithmetischen Ausdrucks. |
Klammern | ( ... ) | Durch Klammern können die arithmetischen Ausdrücke gruppiert werden, um z.B. die Vorrangregeln der Operationen außer Kraft zu setzen. Klammerausdrücke können beliebig geschachtelt werden und die Klammern werden dabei immer von innen nach aussen berechnet. |
Zum Abschluß noch ein paar Beispiele, die einige Besonderheiten der arithmetischen Expansion exemplarisch verdeutlichen sollen.