Betriebssysteme UNIX/Linux Übungsthema 7 “die Shell und Shell-Skripte” Dirk Wenzel Dr. Jörg Gruner SS 2006 Inhalte: Shell und Shell-Skripte Shell-Variable und die Systemumgebung einfache Shell-Skripte fortgeschrittene Shell-Skripte Start-Up Shell-Skripte 1. Die Shell und Shell-Skripte Eine Shell ist ein Programm, das Benutzerkommandos liest und ausführt. Zudem unterstützen Shells die Kontrolle über Programme, die Ein- und Ausgabe-Umleitung sowie eine eigene Kommandosprache um Shell-Skripte zu schreiben. Ein Shell-Skript ist eine einfache Textdatei, die eine Reihe von Kommandos einer Shell-Kommando-Sprache enthält (wie eine Batch-Datei unter Windows, z.B. autoexec.bat). Es sind viele unterschiedliche Shells unter UNIX-Systemen verfügbar (z.B. sh, bash, csh, ksh, tcsh, usw.), wovon jede eine eigene Kommandosprache unterstützt. Hier wollen wir die Kommandosprache der Bourne-Shell (sh) verwenden, da sie in den meisten UNIX-Systemen zur Verfügung steht. Sie wird auch von der bash und der ksh unterstützt. 2. Shell Variablen und die Systemumgebung In einer Shell können, wie in den meisten Programmiersprachen, Variablen definiert werden. Eine Variable hat einen Namen und einen Inhalt. Wurde einer Variablen ein Wert zugewiesen, so kann er mit dem Zeichen $ ausgelesen werden. Beispiel: > bob='hello world' > echo $bob hello world > In der aktuellen Shell erzeugte Variabele sind lokal und somit nur in dieser Shell ansprechbar. Mit dem Kommando set wird eine Liste aller Variablen angezeigt, die momentan in der Shell definiert sind. Sollen Variable auch für Kommanos außerhalb der Shell verfügbar sein, kann man sie in die Umgebung (environment) exportieren. > export bob //unter csh wird setenv verwendet! Die Umgebung (environment) ist eine Sammlung von Variablen, die den Kommandos bei deren Ausführung (einschließlich der Shell) zur Verfügung stehen. UNIX Kommandos und Programme können die Werte von Umgebungsvariablen lesen und sich dementsprechend verhalten. So wird z.B. die Umgebungsvariable PAGER vom man Kommando (und auch noch von anderen) ausgelesen, um festzustellen, mit welchem Kommando Multiseiten angezeigt werden. Beispiel: Setzen Sie die Umgebungsvariable wie folgt > export PAGER=cat Dirk Wenzel, Dr. Jörg Gruner Seite 1 und starten Sie das man-Kommando (z.B. man pwd). Die Seite wird nun ohne anzuhalten über den Monitor fliegen. Setzen Sie PAGER nun auf more und testen Sie erneut mit man pwd. > export PAGER=more Eine weitere oft genutzte Umgebungsvariable ist EDITOR, welche den Standardeditor definiert. Sie können diese auf vi, emacs oder einen anderen Editor ihrer Wahl setzen. Um herauszufinden, welche Umgebungsvariable alle von einem bestimmten Kommando verwendet werden, müssen die man-pages zu Rate gezogen werden. Eine weitere interessante Umgebungsvariable ist PS1, die den Promptstring (das sind die Zeichen, die links von der Eingabemarke stehen) der Shell festlegen. Beispiel: > export PS1="(\h) \w> " (lumberjack) ~> So können z.B. für die bash folgende Zeichen verwendet werden: \h aktueller Host \w aktuelles Arbeitsverzeichnis \d Datum \t Zeit \u aktueller Benutzer weitere Infos finden Sie in den man-pages zur bash Eine weitere viel genutzte Umgebungsvariable ist PATH. Sie beinhaltet eine Liste von Pfadangaben, in denen die Shell nach ausführbaren Programmen sucht. Ist z.B. PATH gesetzt wie folgt: /bin:/usr/bin:/usr/local/bin:. und Sie geben das Kommando ls ein, wird die Shell in /bin, /usr/bin usw. nachschauen, ob es dort zu finden ist und dann ausführen. Ansonsten kommt eine Fehlermeldung. Achten Sie darauf, dass auch das aktuelle Arbeitsverzeichnis gesetzt ist '.'. Somit können Sie erstellte Shellskripte und Programme in deren aktuellem Verzeichnis ausführen, ohne immer "./" (also: ./myprogramm) voranstellen zu müssen! Beachten Sie, dass PATH nichts mit Angaben von Argumenten hinter dem Kommando zu tun hat. So wird für cat myfile.txt nur nach ./myfile gesucht und nicht nach /bin/myfile.txt usw. 3. einfache Shell-Skripte So sieht ein ganz einfaches Schellskript aus, welches in einem Texteditor erstellt wurde und den Dateinamen simple hat. #!/bin/sh # Dies ist ein Kommentar Dirk Wenzel, Dr. Jörg Gruner Seite 2 echo echo echo echo echo read echo "Die Anzahl der Argumente ist $#" "Die Argumente sind $*" "Das erste ist $1" "Meine Prozess-ID ist $$" "Geben Sie eine Zahl über die Tastatur ein: " number "Die eingegebene Nummer lautet $number" Das Shellskript beginnt mit der Zeile "#!/bin/sh". Normalerweise bezeichnet "#" eine Kommentarzeile, aber "#!" ist eine besondere Kombination, die UNIX mitteilt, dass die Bourne-Shell (sh) zur Ausführung des Skripts verwendet werden soll. Die Zeichenfolge "#!" muss ganz am Anfang des Skripts stehen, also die ersten beiden Zeichen. Die Argumente, die dem Skript mit übergeben werden, können mit $1, $2, $3 usw. angesprochen werden. das $* steht für alle Argumente und $# steht für die Anzahl der Argumente. Die Prozess-ID (PID) der Shell, die das Skript gerade ausführt, wird mit $$ ausgegeben. Der Befehl read liest Zeichen über die Tastatur ein und schreibt sie in die Variable number. Um das Skript nun starten zu können, muss es zuerst ausführbar gemacht werden! > ls –l simple -rw-r—r-1 user group 245 Nov 27 > chmod +x simple > ls –l simple -rwxr—xr-x 1 user group 245 Nov 27 > ./simple hello world Die Anzahl der Argumente ist 2 Die Argumente sind hello world Das erste ist hello Meine Prozess-ID ist 1783 Geben Sie eine Zahl über die Tastatur ein: 24 Die eingegebene Nummer lautet 24 > simple simple 4. fortgeschrittene Shell-Skript Programmierung if-then-else Anweisung Shell-Skripte unterstützen einfache Ja/Nein-Abfragen (bedingte Anweisungen). Syntax: if [ test ] then kommandos-wenn-test-wahr-ist else kommandos-wenn-test-falsch-ist fi Die test Bedingung kann auf Dateieigenschaften, einfache Zeichenketten oder numerische Vergleiche angewandt werden. Die eckige Klammer "[" steht für ein Kommando (/bin/[), welches die Überprüfung der test-Bedingung unterstützt. Dazu Dirk Wenzel, Dr. Jörg Gruner Seite 3 müssen allerdings Leerzeichen zwischen den eckigen Klammern und der test-Bedingung sein. Liste grundlegender test-Bedingungen: -s file -f file -d file -r file -w file -x file $X –eq $Y $X –ne $Y $X –lt $Y $X –gt $Y $X –le $Y $X –ge $Y "$A" = "$B" "$A" != "$B" $X ! –gt $Y $E –a $F $E –o $F wahr wenn file existiert und nicht leer ist wahr wenn file eine einfache Datei ist wahr wenn file ein Verzeichnis ist wahr wenn file lesbar ist wahr wenn file beschreibbar ist wahr wenn file ausführbar ist wahr wenn X gleich Y ist wahr wenn X ungleich Y ist wahr wenn X kleiner Y ist wahr wenn X größer Y ist wahr wenn X kleiner gleich Y ist wahr wenn X größer gleich Y ist wahr wenn Ausdruck A gleich Ausdruck B ist wahr wenn Ausdruck A ungleich Ausdruck B ist wahr wenn Ausdruck X nicht größer Ausdruck Y ist wahr wenn Ausdruck E und F beide gleich (AND) wahr wenn Ausdruck E oder F beide gleich (OR) for Schleifen Manchmal ist es nötig, eine Liste von Dateien zu durchlaufen und auf jede Datei ein Kommando anzuwenden. Dies kann mit einer for-Schleife geschehen: for variable in list do kommandos done //beziehen sich auf $variable Das folgende Skript sortiert alle Textdateien im aktuellen Verzeichnis: #!/bin/sh for f in *.txt do echo sorting file $f cat $f | sort > $f.sorted echo sorted file has been output to $f.sorted done while Schleifen Eine weitere Schleifenart ist die while-Schleife: while [ test ] do kommandos done Dirk Wenzel, Dr. Jörg Gruner Seite 4 Das folgende Skript wartet, bis eine nicht leere Datei input.txt erzeugt wurde: #!/bin/sh while [ ! –s input.txt ] do echo waiting ... sleep 5 done echo input.txt is ready Sie können ein Shell-Skript mit der exit-Anweisung an einer beliebigen Stelle abbrechen. Beispiel: #!/bin/sh while [ ! –s input.txt ] do if [ -s input.txt ] echo input.txt is ready exit fi echo waiting ... sleep 5 done case Anweisung Die case-Anweisung ist eine weitere Möglichkeit, Bedingungen abzufragen. Der auszuwertende Ausdruck wird mit mehreren Alternativen verglichen. case variable in pattern1) kommandos (wird ausgeführt, wenn variable auf pattern1 zutrifft) ;; pattern2) kommandos (wird ausgeführt, wenn variable auf pattern2 zutrifft) ;; usw. esac Das folgende Skript verwendet die case-Anweisung, um eine Auswahl von Dateien, die nicht ausführbar sind, zutreffen und nach ihrer Dateiendung (extension) zu charakterisieren. Beachten Sie, wie der OR-Operator "|" eingesetzt wird, um nach multiplen Ausdrücken zu suchen, wie "*" eingesetzt wird, um alle Treffer auszuwerten und die Wirkung von sogenannten forward single quotes "`". #!/bin/sh for f in $* do if [ -f $f –a ! –x $f ] then Dirk Wenzel, Dr. Jörg Gruner Seite 5 done fi case $f in core) echo "$f: a core dump file" ;; *.c) echo "$f: a C programm" ;; *.cpp|*.cc|*.cxx) echo "$f: a C++ programm" ;; *.txt) echo "$f: a text file" ;; *.pl) echo "$f: a PEARL script" ;; *.html|*.htm) echo "$f: a web document" ;; *) echo "$f: appears to be "`file –b $f` ;; esac Umleitung der Ausgabe von Kommandos in eine Variable Jedes UNIX Kommando kann, anstelle über die Kommandozeile, ebenso von einem ShellSkript ausgeführt werden. Die Ausgabe eines Kommandos kann darin mit Hilfe der forward single quotes (``) in eine Variable geschrieben und weiterverwendet werden: #!/bin/sh lines=`wc –l $1` echo "Die Datei $1 hat $lines Zeilen" Dieses Skript gibt die Anzahl der Zeilen in der Datei aus, die den ersten Parameter enthalten. arithmetische Operationen Die Bourne-Shell hat keine Implementierungen um einfache mathematische Ausdrücke auszuwerten. Das UNIX-Kommando expr kann stattdessen dazu verwendet werden. Es wird oft in Shell-Skripten mit forward-single-quotes verwendet, um die Werte von Variablen zu aktualisieren. Beispiel: lines = `expr $lines + 1` addiert 1 zu der Variablen lines dazu. expr unterstützt die Operatoren +, -, *, /, %(remainder), <, <=, =, !=, >=, >, |(OR) und &(AND). 5. Start-Up Shell-Skripte Dirk Wenzel, Dr. Jörg Gruner Seite 6 Beim ersten Einloggen in eine Shell arbeitet diese ein systemweites start-up-Skript ab. Gewöhnlich ist dies /etc/profile bei sh, bash und ksh und /etc/.login bei der csh. Dann wird in Ihrem Homeverzeichnis nach eigenen start-up-Skripten weitergesucht, also .profile bei sh, bash und ksh und .cshrc bei der csh und tcsh. Ihr eigenes start-upSkript ist somit ein guter Platz, um eigene Umgebungsvariable abzusetzen wie z.B. PATH, EDITOR oder auch selbst definierte. So kann z.B. das Verzeichnis ~/bin zur Umgebungsvariable PATH in der bash wie folgt in .profile hinzugefügt werden: > source ./profile Um nun die Änderungen für die aktuelle Shell zu aktuallisieren, geben Sie > . ./profile oder export PATH=$PATH:~/bin ein. Das Kommando source ist in der Shell eingebaut. Es stellt sicher, dass Änderungen in der Umgebung, also dem environment, die in .profile vorgenommen wurden, sich auch in der aktuellen Shell auswirken. Dirk Wenzel, Dr. Jörg Gruner Seite 7 Übungsblatt 7: “die Shell und Shell-Skripte” 1. Erstellen Sie mit ihrem Lieblings-Editor (das ist doch jetzt bestimmt der vi, oder ☺) das Shell-Skript simple aus Kap.3. Starten Sie es anschließend und schauen Sie, wie sich die Inhalte auf die Ausgabe auswirken. 2. Erweitern Sie das Skript so, dass Sie in die Variable ratemich eine geheime Zahl zwischen 1 und 100 schreiben. Lassen Sie ihren Nachbarn dann die richtige Zahl erraten. Das Skript soll Hinweise geben wie z.B. "Sorry, Ihre Schätzung ist zu niedrig!", "Sorry, Ihre Schätzung ist zu hoch!" oder "Vollltreffer!". 3. Schreiben Sie ein Shell-Skript, dass alle .txt Dateien in .text umbenennt. Das Kommando basename könnte hier hilfreich sein. Erzeugen Sie in einem Verzeichnis ein paar Dateien .txt (ohne Inhalt) und testen Sie das Skript. 4. Schreiben Sie ein Shell-Skript pidof, welches einen Namen als Parameter übernimmt und den PID bzw. die PIDs von Prozessen mit diesem Namen ausgibt. 5. Shell-Skripte können auch Funktionen enthalten. Funktionen werden wie folgt deklariert: funcname() { Anweisungen } und aufgerufen mit funcname param1 param2 ... . Die Parameter sind innerhalb der Funktion über $1, $2 usw. ansprechbar. Fügen Sie nun die Funktion usage() dem pidof-Skript hinzu, welches dem Anwender Informationen zum Umgang mit dem Skript ausgibt. Rufen Sie usage() auf, wenn eine falsche Anzahl an Parametern beim Aufruf von pidof übergeben wird. 6. Modifizieren Sie ihr .bashrc start-up-Skript so, dass die PATH-Variable das aktuelle Verzeichnis "." enthält und die Umgebungsvariable EDITOR auf vi, emacs oder einen Editor Ihrer Wahl gesetzt ist. Starten Sie das modifizierte Skript mit source .bashrc und prüfen Sie, ob die Änderungen in der aktuellen Shell funktioniert haben. Verwenden Sie dazu das Kommando set bzw. env. Dirk Wenzel, Dr. Jörg Gruner Seite 1