Page 1


Exit Status

Jedes Kommando liefert einen Exit Status zuruck. Der Exit Status

ist ein Integerwert zwischen 0 und 255. 0 bezeichnet den Erfolg des

Kommandos, alle anderen Werte bezeichnen verschiedene Ausmaße

des Scheiterns. Der Exit Status des letzten Kommandos steht in der

Variable $?.

$ grep root /etc/passwd

root:x:0:0:root:/root:/bin/bash

$ echo $?

0

$ grep Administrator /etc/passwd

$ echo $?

1

$ true

$ echo $?

0

$ false

$ echo $?

1

Die Programme true beziehungsweise false dienen einzig und allein

dazu Exit Status 0 beziehungsweise 1 zu liefern. Das scheint auf den

ersten Blick sinnlos, aber das tut auch /dev/null.

Um den Exit Status eines Shell Scripts zu beeinflussen, gibt es den

built-in Befehl exit. Dieser beendet ein Script sofort und setzt einen

anzugebenden Wert als Exit Status des Scripts. Das Script namens

parameterexists liefert Exit Status 0, wenn mindestens ein Parameter

übergeben wurde. Andernfalls liefert es Exit Status 1.

#!/bin/bash


if [ $1 ]; then

exit 0

else

exit 1

fi

Man sollte dabei umbedingt die Konvention beachten, daß 0 fur einen

Erfolg steht, während andere Zahlen als Mißerfolg interpretiert wer-

den.



Exit Status

Jedes Programm liefert einen Exit Status

zurück.

0 steht fur eine erfolgreiche Beendigung des

Programms

1-255 bezeichnet verschiedene Ausmaße des

Scheiterns.

Der Exit Status eines Shell Scripts kann über

den bash built-in Befehl exit gesteuert werden.

Der Exit Status des letzten ausgeführten

Kommandos steht in der Variable $?.



Page 2



Flow Control

Unter Flow Control versteht man Kontrollstrukturen wie bedingtes

Ausfuhren von Kommandos und Schleifen. Im Wesentlichen sind dies

if, case, for und while. Wir werden diese im Weiteren nachein-

ander abhandeln, wobei wir nebenbei allerlei Nützliches mitnehmen

werden. Zuerst wenden wir uns dem if zu, von dem wir schon ein

Beispiel sahen. Im folgenden Syntaxüberblick wird bei zutreffen von

Bedingung1 die Anweisung1 ausgeführt. Trifft Bedingung1 nicht, Be-

dingung2 aber schon zu, so wird Anweisung2 ausgefuhrt. Trifft keine

der beiden Bedingungen zu, so wird Anweisung3 ausgeführt.



Flow Control, if

Die if-Anweisung erlaubt eine bedingte

Ausfuhrung von Kommandos und ist dem if in

Programmiersprachen sehr ähnlich. Es verlangt

nach folgender Syntax:

if Bedingung1

then

Anweisung1

elif Bedingung2

then

Anweisung2

else

Anweisung3

fi

wobei sowohl der elif, als auch der else-Block

optional sind. Die Bedingung ist ein

Kommando, dass 0(true) oder ungleich 0 (false) als

Exit Status zurückgibt.




Page 3




Bedingungen

Um ein if formulieren zu konnen, müssen wir wissen, was eine Be-

dingung ist. Eine Bedingung ist nichts anderes als ein Kommando. Ist

dessen Exit Status 0, so gilt die Bedingung als erfüllt. Andernfalls gilt

sie als nicht erfüllt. Das erklart auch, warum man den Konventionen

des Exit Status in eigenen Scripts folgen sollte.

Ein in Bezug auf Bedingungen besonders wertvoller Befehl ist der

built-in Befehl test. Will man zum Beispiel feststellen, ob der Inhalt

der Variable TEST gleich “rose” ist, so kann man das so überprufen:

$ TEST=rose

$ test $TEST = rose

$ echo $?

0

$ TEST=eros

$ test $TEST = rose

$ echo $?

1

Als Synonym für test können auch eckige Klammern [ ] verwendet

werden, wobei darauf zu achten ist, daß nach der öffnenden und vor

der schließenden Klammer Leerzeichen stehen.

$ TEST=rose

$ [ $TEST = rose ]

$ echo $?

0



Bedingungen (Strings, Dateien)

Das ist eine unvollständige Liste von Tests mit

Strings (Zeichenketten) und Dateien. In

folgender Liste bezeichnen S1 beziehungsweise

S2 Strings und D1 beziehungsweise D2

Dateinamen.

Test

Wahr wenn

[ S1 = S2 ]

Strings ident

[ S1 != S2 ]

Strings nicht ident

. . .

[ -e D1 ]

Datei D1 existiert

[ -d D1 ]

D1 ist ein Verzeichnis

[ -x D1 ]

D1 ist ausführbar

[ D1 -nt D2 ] D1 neuer als D2

. . .


Bedingungen (Integers)

Die folgenden Tests gehen davon aus, dass in

den Variablen A und B ganze Zahlen stehen. Ist

dies nicht so, so gibt es eine Fehlermeldung.

Test

Wahr wenn

[ $A -lt $B ] $A kleiner als $B

[ $A -gt $B ] $A größer als $B

[ $A -le $B ] $A kleiner gleich $B

[ $A -ge $B ] $A größer gleich $B

[ $A -eq $B ] $A gleich $B

[ $A -ne $B ] $A ungleich $B




Page 4


Arithmetik

Neben der Möglichkeit ganze Zahlen gegeneinander zu testen, kann

man in der Shell mit ganzen Zahlen auch Rechnen. Ausdrücke, die mit

$[ ] oder $(()) umschlossen sind werden als ganzzahlige Rechenope-

rationen ausgelegt und auszuwerten versucht.

$ echo "1+1=$[1+1]"

1+1=2

$ echo "3*3=$((3*3))"

3*3=9

$ echo "11/4=$[11/4] mit Rest $[11%4]"

11/4=2 mit Rest 3

In der Programmierung ist es häufig gefragt, den Inhalt einer Variable

zu inkrementieren, sprich um 1 zu erhöhen. Das sieht in C definitiv

schöner aus, als in der bash:

$ N=1

$ echo $[$N+1]

2

Um in der Shell oder innerhalb von Scripts Gleitkommarechnungen

oder allgemein kompliziertere Rechnungen durchzuführen, sei dem Le-

ser bc und dc ans Herz gelegt.


Arithmetik

Integerarithmetik wird innerhalb eckiger oder

doppelter runder Klammern ausgewertet.

$ echo $[1+1]

$ echo $((1-1))

Eine unvollstandige Liste der existierenden

Operatoren:

Operator Bedeutung

+

Plus

-

Minus

*

Multiplikation

/

Division

%

Modulo

**

Exponent

Das Inkrementieren einer Variable funktioniert

folglich so:

$ N=1

$ N=$[$N+1]

$ echo $N


Page 5


Bedingungen Verknüpfen

Neben dem if gibt es noch eine einfachere, eingeschränkte Möglichkeit

des bedingten Ausführens von Kommandos. So wird im Folgenden der

Befehl ls nur ausgeführt, wenn die Programmdatei /bin/ls existiert

und ausführbar ist:

$ [ -x /bin/ls ] && ls

helloworld parameterexists parameters

Der Exit Status solch einer Kette von Kommandos ist der Exit Status

des letzten ausgeführten Kommandos. Ein weiteres Beispiel legt eine

Datei foo nur an, wenn diese noch nicht existiert:

$ touch foo

$ ls

foo

$ [ -e foo ] || touch foo

$ echo $?

0

$ [ ! -e foo ] && touch foo

$ echo $?

1


Bedingtes Ausführen

In folgender Zeile wird Kommando2 ausgeführt,

wenn Kommando1 Exit Status 0 hat.

$ Kommando1 && Kommando2

Während in folgender Zeile Kommando2

ausgeführt wird, wenn Kommando1 Exit Status

= 0 hat.

$ Kommando1 || Kommando2

Der Exit Status dieser Zeilen ist der Exit

Status des letzten ausgefuhrten Kommandos.

Ein ! vor einem Kommando verneint den Exit

Status.

Operator Bedeutung

&& -- Und

|| -- Oder

! -- Nicht




Dies kann auch dazu benutzt werden

verknupfte Bedingungen in einer if-Anweisung

zu erstellen.


Page 6


Flow Control, case

Eine spezielle und für manche Anwendungen

sehr angenehme Variante der if-Anweisung ist

die case-Anweisung, die nach folgender Syntax

verlangt.

case Ausdruck in

Pattern1)

Anweisungen ;;

Pattern2)

Anweisungen ;;

...

esac

Das bietet sich zum Beispiel dazu an, um

Switches zu realisieren. Wie bei init-scripts

üblich, erlaubt folgendes Script eine “start” und

stop” Option:

case $1 in

start) ...;;

stop) ...;;

*) Usage: ...;;

esac


Die case-Anweisung wird oft in init Scripts verwendet. Diese Scripts

dienen zum starten und stoppen von Systemdiensten. Üblicherweise

liegt für jeden Systemdienst im Verzeichnis /etc/init.d/ (manchmal

auch /etc/rc.d/init.d oder /etc/rc.d/) ein Script, dass diese die

Parameter start, stop oder restart versteht.

$ cat /etc/init.d/inetd

#!/bin/sh

#

# start/stop inetd super server.

[...]

case "$1" in

start)

echo -n "Starting internet superserver:"

[...]

;;

stop)

echo -n "Stopping internet superserver:"

[...]

;;

restart)

echo -n "Restarting internet superserver:"

[...]

;;

*)

echo "Usage: /etc/init.d/inetd {start|stop|restart}"

exit 1

;;



Page 7

Gibt man einen Parameter an, der nicht angeführt ist, so wird der

Punkt unter *) ausgefuhrt. Dieser klärt über die richtige Benutzung

des Scripts auf und beendet das Script mit Exit Status 1.

Die for-Schleife unterscheidet sich stark von for-Schleifen anderer

Programmiersprachen. In ihr durchläuft ein Variable alle Werte einer

Liste. Die Eintrage dieser Liste sind durch Leerzeichen, Tabulatoren

oder Zeilenumbruch getrennt. Alle Frauen sind herzlichst dazu einge-

laden das Script polygam nach ihren Bedürfnissen zu modifizieren.

#!/bin/bash

LISTE="Liese Ingrid Stefanie Frauke"

for FRAU in $LISTE; do

echo "$FRAU ist meine Frau."

done

Eine Möglichkeit einer Konstruktion eines in anderen Sprachenübli-

chen for ist die Folgende:


Flow Control, for

Die for-Schleife der bash ist in ihrer Syntax

substanziell verschieden zu vielen

Programmiersprachen.

for Name in Liste

do

Anweisungen

done

Der Inhalt der Variable Name durchläuft dabei

alle Elemente der Liste Liste. So spielt der

folgende Code alle mp3-Dateien im aktuellen

Verzeichnis ab.

for LIED in *.mp3

do

mpg123 $LIED

done

mpg123 ist dabei der mp3-Player. *.mp3 wird

von der Bash zu einer Liste aller Dateien mit

der Endung .mp3 expandiert.


Page 8


Command Substitution

Oft will man an einer bestimmten Stelle in einem Script die Ausgabe

eines Kommandos platzieren. Das nennt man Command Substitution

und läßt sich auf zwei Arten realisieren. Das Kommando wird entwe-

der mit Backticks ‘‘ oder mit $() umschlossen. Das Script summerton

ist der Telefonzeitansage nachempfunden:

#!/bin/bash

# Zeitausgabe ala Zeitansage per Telefon

# Warten bis zu den naechsten vollen 10 Sekunden

while [ $[‘date +%S‘%10] -ne 0 ]; do

sleep 1

done

# Alle 10 Sekunden Zeitansage

while true; do

echo "Es wird mit dem Summerton ‘date +%k‘ Uhr, \

date +%M‘ Minuten und ‘date +%S‘ Sekunden."

sleep 10

done

Die Frage ob man ‘‘ oder $() verwendet ist nicht ganz irrelevant. Die

Verwendung von $() hat den Vorteil, daß man diese Konstruktion in-

einander Verschachteln kann. Der Nachteil ist, daß diese Konstruktion

in der bash, nicht jedoch in der sh existiert. Versucht man ein Script,

dass $() verwendet auf einem System ohne einer bash zu verwenden,

so wird dies scheitern.


Das übliche For I

Um das in anderen Programmiersprachen übliche Verhalten einer for-

Schleife zu erhalten kann folgender Code in usualfor1 dienen:

#!/bin/bash

# Immitiert ein for wie in C, wobei dies einem

# for(int i=$START, i<=$STOP, i=i+$STEP) entspricht

START=1; STOP=10; STEP=3

for N in ‘seq $START $STEP $STOP‘

do

echo $N

done

$N durchläuft alle Werte von $START bis $STOP in Abständen von

$STEP.

Zur Command Substitution werden hier Backticks (‘‘) verwendet,

was die Portabilitat des Codes erhoht. In den meisten Fallen kann auf

eine einfachere Syntax von seq zurückgegriffen werden. Siehe dazu

$ man seq


Page 9


Flow Control, while, until

Die while- bzw. until-Schleife entspricht ihren

Entsprechungen in anderen

Programmiersprachen. Ein Anweisungsblock

wird, solange eine Bedingung wahr bzw. nicht

wahr ist, ausgeführt.

while Bedingung

do

Anweisungen

done

Als Beispiel ein Codesegment, das alle 5

Sekunden schaut, ob eine Modemverbindung

existiert und falls diese zusammengebrochen ist

eine Funktion namens reconnent() ausführt.

while ifconfig | grep ppp0

do

sleep 5

done

reconnect()


Das übliche For II

Eine weitere Methode das in anderen Programmiersprachen übliche

for zu erhalten ist die folgende Umschreibung in usualfor2, die naturlich

nicht Shell spezifisch ist:

#!/bin/bash

# umschreibt ein for wie in C

# durch ein while

START=1; STOP=10; STEP=3

N=$START

while [ $N -le $STOP ]; do

echo $N

N=$[$N+$STEP]

done

Auch hier durchläuft $N alle Werte von $START bis $STOP in Abständen

von $STEP.



Quellen

1. Manpage

$ man bash

2. Bücher

Learning the Bash Shell,

Newham & Rosenblatt, O’ Reilly

3. Webpages


http://www.gnu.org/software/bash/manual/bashref.html


http://www.linux.se/doc/HOWTO/Adv-Bash-Scr-HOWTO/index.html


http://www.gi.kernel.org/sites/www.linuxdoc.org/LDP/LG/issue25/dearman.html[textonly]


http://www.dcc.unicamp.br/~celio/mc514/bash/bash-tute.html


4. Vorhandene Scripts

/etc/init.d/*

/.bashrc