Scripte
Übersicht über das Konsolen-Tutorial
Vorbemerkung[Bearbeiten]
Ein Script ist eine Textdatei, die Kommandos der Shell enthält. Diese Datei wird aber erst dann zum Script, wenn das Dateirecht "Ausführen" erteilt ist.
Einfaches Beispiel[Bearbeiten]
Uns interessiert regelmäßig, wie die Festplattenbelegung des Systems aussieht und wieviel Platz der Mail-Ordner belegt. Dazu schreiben wir ein Script:
sudo cat >/usr/local/bin/DFree <<EOS
#! /bin/bash
# Festplattenbelegung in lesbarer Form (-h für "human readable")
df -h
# Und speziell der Platzbedarf des Mail-Ordners:
du -sh ~/mail
EOS
- Kommentare werden mit # am Zeilenanfang gekennzeichnet. Genau formuliert: Ist das erste Nichtleerzeichen einer Zeile ein '#', ist die Zeile ein Kommentar.
- Die erste Zeile eines Scripts muss ein spezieller Kommentar sein: Die Zeile muss mit #! (genannt "Shebang") beginnen, danach muss das Programm angegeben werden, das den Inhalt interpretiert, in unserem Fall also die Bash.
- Es folgen die eigentlichen Kommandos, ergänzt um Kommentare.
Wir setzen das Ausführungsrecht:
sudo chmod uog+x /usr/local/bin/DFree
Ab jetzt verhält sich das neue Script wie ein ganz normales Konsolenprogramm.
Wir haben den Namen DFree so gewählt, dass 3 Tasten zum Aufruf genügen: 'D', TAB und Enter.
Profile[Bearbeiten]
Die Bash kennt zwei spezielle Scripts, die beim Start der Shell ausgewertet werden (wenn nicht per Option anderst gewünscht):
- ~/.bashrc: ~ steht für das Heimatverzeichnis des angemeldeten Benutzers, die Datei ist also benutzerspezifisch.
- /etc/bash.bashrc: Hier gehören also alle Definitionen hinein, die für alle Benutzer relevant sind.
Ablaufsteuerung[Bearbeiten]
Die Shell bietet die elementaren Möglichkeiten einer Programmiersprache: Variablen und Ablaufsteuerung:
Bedingte Kommandos[Bearbeiten]
if [ -e /etc/debian_version ] ; then
echo "Ich bin ein Debiansystem"
else
echo "Zu Debian hat es nicht gereicht..."
fi
In den eckigen Klammern [] wird eine Bedingung angegeben. Trifft diese zu (ist sie wahr), werden die Kommandos ausgeführt, die zwischen then und else stehen, in diesem Fall echo "Ich bin ein Debiansystem". Trifft die Bedingung nicht zu, werden die Befehle zwischen else und fi ausgeführt.
Um Alternativen abzufragen, kann eine ganze Abfrage-Kette gebildet werden:
Hier wird der Rückgabewert des Kommandos wget überprüft:
wget http://mypage.de/index.html
if [ $? = 4 ] ; then
echo "Netzwerkfehler"
elif [ $? = 2 ] ; then
echo "Syntaxfehler bei den Argumenten"
elif [ $= != 0 ] ; then
echo "Fehler aufgetreten"
fi
Hinweis: 'fi' ist die Umkehrung von 'if'. Diese Art der "Klammerbildung" ist alte Unixtradition.
Bedingungen[Bearbeiten]
Als Bedingung wird immer der Rückgabewert eines Programms verwendet: 0 bedeutet wahr, alles anderen falsch.
Das häufigste Programm, das für Bedingungen verwendet wird, ist das Programm test. Der Aufruf von test kann auch mit '[' erfolgen, wie er im Beispiel verwendet wurde: Die Bedingung innerhalb '[' und ']' wird also an test übergeben und von diesem ausgewertet.
Die wichtigsten Optionen des Programms in Beispielen:
# Test, ob $JAVA_HOME ein Leerstring ist:
test -z "$JAVA_HOME"
# test, ob $DIR kein Leerstring ist:
test -n $DIR
# Gleichheit von Strings:
test $DIR = "."
# Ungleichheit von Strings:
test $USER != "root"
# Ganzzahlen: Gleichheit, Ungleichheit, kleiner, groesser, kleiner gleich, groesser gleich:
test $COUNT -eq 1 ; test $COUNT -ne 1 ; test $COUNT -gt 1 ; test $COUNT -lt 1 ; test $COUNT -ge 1 ; test $COUNT -le 1
# Test, ob die Datei passwd juenger als das Backup ist
test /etc/passwd -nt /opt/backup/passwd
# Test, ob die Datei $FILE existiert, ein Vezeichnis, eine "normale" Datei, ein Link ist:
test -e $FILE ; test -d $FILE ; test -f $FILE ; test -L $FILE
# Test, ob die Datei $FILE groesser 0 Byte, lesbar, schreibbar, ausführbar ist:
test -s $FILE ; test -r $FILE ; test -w $FILE ; test -x $FILE
# Bedingungen koennen mit ! invertiert werden:
# Test, ob $JAVA_HOME kein Verzeichnis ist
# test ! -d $JAVA_HOME && echo "kein Verzeichnis: $JAVAHOME"
# Bedingungen verknüpfen:
# Ist $FILE eine "normale" Datei und zusaetzlich schreibbar?
test -f $FILE -a -w $FILE
# Ist $X kleiner 1 oder groesser 10
test $X -lt 1 -o $X -gt 10
Aufzählungsschleife[Bearbeiten]
echo "Zeit;Aktion" >stundenplan.csv
for HOUR in {8..16} ; do
echo "$HOUR:00;" >>stundenplan.csv
done
Hier wird die Variable HOUR definiert, die nacheinander alle Werte annimmt, die zwischen 'in' und ';' stehen. In diesem Fall wird der Ausdruck in den geschweiften Klammern zu den Zahlen 8, 9, ... 16 erweitert, es werden also die Befehle
echo "8:00;" >>stundenplan.csv echo "9:00;" >>stundenplan.csv ... echo "16:00;" >>stundenplan.csv
ausgeführt, und damit eine Vorlage für einen einfachen Stundenplan erstellt.
Bedingte Schleife[Bearbeiten]
Wir erzeugen eine Datei /usr/local/bin/Ewich:
#! /bin/bash
REST=$PATH
while [ $REST != $DIR ] ; do
DIR=${REST%%:*} ; # Entfernen der restlichen Pfade
REST=${$REST#*:} ; # Entfernen des ersten Pfades
test -e $DIR/$1 && file $DIR/$1
done
Dieses Script sucht eine gegebene Datei ($1) in allen Verzeichnissen, die im Suchpfad $PATH stehen. Wird sie dort entdeckt, gibt sie den Informationen über den Dateityp aus.
Die Anweisungen zwischen 'do' und 'done' werden nur ausgeführt, wenn die Schleifenbedingung, also zwischen [ und ], wahr liefert. In diesem Beispiel wird geprüft, ob der $REST von $DIR verschieden ist. Wenn ja, wird das erste Verzeichnis aus dem Restpfad in DIR gemerkt, dann dieses Verzeichnis aus dem Restpfad entfernt. Wenn die Datei in dem so extrahierten Verzeichnis existiert, wird die Info ausgegeben.
Schleife über die Zeilen einer Datei[Bearbeiten]
mapfile -t </etc/passwd LINES
COUNT=${#LINES[@]}
ix=0
while [ $ix -lt $COUNT ]; do
LINE=${LINES[$ix]}
echo ${LINE%:*}
ix=$(expr $ix + 1)
done
Auswahl von Alternativen[Bearbeiten]
case "$1" in
one)
expr $1
;;
two)
echo $1
echo $1
;;
*)
echo "+++ unexpected value: $1"
;;
esac
- Hinter "case" steht der Wert, der getestet wird, hier also "$1".
- Jede Alternative beginnt mit einem String und ')', hier one) etc.
- Es folgt eine Anweisungsliste, die mit ";;" beendet wird.
- Es wird nach der ersten Übereinstimmung der Alternativen gesucht und die Anweisungsliste dieser Alternative ausgeführt, danach wird die case-Anweisung verlassen.
- Beim Vergleich der Alternativen werden Wildcards berücksichtigt. Steht also als letzte Alternative ein *), trifft diese Alternative immer zu. Damit werden alle Werte, die nicht oberhalb definiert sind, hier behandelt.
Scripte und der Export von Variablen[Bearbeiten]
Wird ein Script aufgerufen, wird ein neuer Prozess gestartet (nämlich die Shell, hier Subshell genannt), das dann das Script abarbeitet. Die Variablen, die in der interaktiven Shell definiert sind, sind genau dann auch in der Subshell bekannt, wenn sie mit export definiert werden.
export DIR=/usr/src
Es gibt aber keine Möglichkeit, eine Variable von der Subshell aus zur aufrufenden interaktiven Shell zu bringen.
Allerdings gibt es einen Befehl, ein Script in der interaktiven Shell selber auszuführen, den source-Befehl.
Beispiel:
echo '#! /bin/bash' >/tmp/doit ; echo 'echo "Dir: $DIR"' >>/tmp/doit
echo 'export APPL=/usr/share/applications' >>/tmp/doit ; chmod +x /tmp/doit
DIR=abc
/tmp/doit
Dir:
Der Wert von DIR wurde also nicht vererbt.
Jetzt mit dem export-Befehl:
export DIR=/abc
/tmp/doit
Dir: /abc
Aber die Definition von APPL ist nicht verfügbar:
echo "APPL: $APPL"
APPL: /usr/share/applications
Die Definition von APPL wird durch den source-Befehl verfügbar:
source /tmp/doit
echo "APPL: $APPL"
APPL: /usr/share/applications