Übersicht
Shell-Scripts (Kommandoprozeduren) können mit Batch-Dateien unter MS-Dos verglichen werden, sind jedoch wesentlich leistungsfähiger.
Ein Shell-Script ist eine Textdatei, in der Kommandos gespeichert sind. Es stellt selbst ein Kommando dar, da es wie ein Systemkommando, auch mit Parametern, aufgerufen werden kann. Shell-Scripts dienen der Arbeitserleichterung und (nach ausreichenden Tests) der Erhöhung der Zuverlässigkeit, da sie gestatten, häufig gebrauchte Sequenzen von Kommandos zusammenzufassen.
Ein Anwendungsbeispiel wäre das nächtliche Kopieren von wichtigen Daten auf einen anderen Rechner im Netzwerk, oder das bearbeiten (z.B. umbenennen oder Rechte setzen) vieler Datein auf einen Schlag.
Es gibt unzählige weitere Anwendungsmöglichkeiten.
Voraussetzungen
Um dieses Tutorial durchführen zu können, benötigen wir Zugang zu einem Unix-Rechner (Linux, OS X).
Stellt dies kein Problem dar sollten wir und mit der Navigation in der Verzeichnis-Struktur des Systems schon einmal befasst haben. Sprich: das wechseln in ein anderes Verzeichnis, wissen, was das Home-Verzeichnis ist und wie wir da wieder hin kommen.
Das ist aber auch schon alles, was wir an Voraussetzungen benötigen.
Was bringt mir dieses Tut?
Am Ende dieses Tutorials haben wir einen kleinen Überblick über Standard-Kontrollstrukturen und Grund-Befehle, die in fast jedem Shell-Script vorkommen.
Wir versuchen einen Wissensstand zu erlangen, so dass wir in Zukunft eine Problemstellung erkennen und wissen, wie wir an die Lösung heran gehen.
Dazu gehört auch das Wissen, es gibt unzählige weitere Möglichkeiten / Tools (einige werden wir kennen lernen), die wir zur Lösung unseres Problems verwenden können.
Kurz: wir eignen uns hier die Basics an...
Fangen wir langsam an...
-- Erste Ausgabe --
;-) Was wollen wir machen?
Wir öffnen die Konsole (Terminal) und legen am besten erst mal einen Ordner an, in dem wir alle unsere Scripte ablegen. Nennen wir den Ordner beispielsweise "shellscripte":
(alles was ab jetzt in den Code-Bereichen steht, spielt sich im Terminal / in der Konsole ab!)
jetzt wechseln wir mit dem Befehl "cd" in das soeben angelegte Verzeichnis
Nun machen wir uns an das Script. Da der Konsolen-Editor vi auf jedem Unixrechner installiert ist, werden wir unsere Scirpte damit schreiben.
Zuerst aber legen wir die Datei mit dem Namen "01_ausgabe" an
Eine Dateiendung ist nicht notwendig. Hin und wieder sieht man solche Scripte mit der Dateiendung .sh, ist aber, wie schon erwähnt, nicht notwendig.
Jetzt öffnen wir mit dem vi-Editor die ebend angelegte Datei
Wenn der vi geöffnet ist, ist der Editor noch im Kommandomodus, um, diverse Befehle einzugeben (z.B. Zeilennummerierung). Um jetzt eine Eingabe machen zu können, wechseln wir durch das drücken der i-Taste in den Einfügemodus und tippen mal folgenden Einzeiler ein:
Um den Einfügemodus wieder zu verlassen tippen wir einfach einmal kurz auf die ESC-Taste.
Jetzt wollen wir das Script speichern und den vi verlassen. Dazu drücken wir bei gedrückter Shift-Taste zwei mal die Z-Taste drücken.
(wesentlich bekannter ist die Variante an dieser Stelle :wq einzugeben und mit Enter zu bestätigen. Jeder so wie er es mag... )
Jetzt befinden wir uns wieder direkt in der Konsole und können unser Script testen
Nachdem wir den Befehl mit Enter bestätigt haben, wird "Hallo Welt" ausgegeben und wir haben unser erstes Script erfolgreich abgeschlossen.
-- Benutzereingaben --
;-) Was wollen wir machen?
Legen wir das script an und öffnen es zum Bearbeiten mit dem vi.
Nachdem wir mit der i-Taste in den Eingabemodus gewechselt haben, füllen wir es mit folgendem Code:
Schauen wir uns an, was dort geschieht.
Mit dem Schlüsselwort "clear" wird die Konsole 'aufgeräumt', sprich: der Inhalt gelöscht. Werden wir gleich sehen, wenn wir das Script ausführen.
Wir wollen uns gleich von Anfang an angewöhnen, die Übersicht zu behalten. Darum auch nach "clear" eine Leerzeile.
Was "echo" und bringt, wissen wir ja bereits. Neu ist hier nur das Argument '-n'. Mit diesem Argument geben wir an, dass der Cursor am Ende der Ausgabe stehen bleiben soll, so dass wir unseren Namen in der gleichen Zeile eingeben müssen.
Das Werkzeug "read" nimmt dann unseren eingegebenen Namen entgegen und speichert ihn in der Variable 'name'.
Mit dem nun folgenden "echo"-Befehl fügen wir einfach nur eine Leerzeile bei der späteren Ausgabe ein.
Nun kommen wir zur eigentlichen Ausgabe.
Gar nicht schwer! Wir nehmen die eben gefüllte Variable 'name' mit in unsere Ausgabe auf.
Uns fällt auf, dass dort plötzlich ein Doller-Zeichen vorangestellt ist. Immer wenn wir an den Wert einer Variable wollen, also den Inhalt auslesen möchten, schreiben wir ein $-Zeichen vor die Variable.
Speichern wir wieder mit gedrückter Shift-Taste und zweimaligen drücken der z-Taste und führen das Script aus.
Wir werden aufgefordert unseren Namen einzugeben und sehen nachdem Bestätigen mit der Enter-Taste etwa folgendes auf unserem Bildschirm:
So wie wir eben einen String (eine Zeichenkette; unseren Namen) eingelesen haben, ist auch das Einlesen von Zahlen kein Problem - dazu ebenfalls ein kleines Beispiel.
Dazu legen wir keine neue Datei an. Wir erweitern das Script von eben, also öffnen wir es mit vi, indem wir das zu öffnende Script direkt als Argument mit übergeben.
Um nun schreiben zu können drücken wir wieder die i-Taste und ergänzen das Script um die fett gedruckten Zeilen.
Mit den zwei Tastenfolgen ESC, gefolgt von Shift + Z Z verlassen wir den Editor.
Rufen wir das Script jetzt auf,
werden wir aufgefordert, zusätzlich zu unserem Namen, noch unser Alter einzugeben und bekommen nun eine erweiterte Ausgabe.
Ich denke, das Prinzip ist klar )
-- Ein wenig rechnen --
;-) Was wollen wir machen?
"expr" ist ein mächtiges Rechenwerkzeug. Ein paar Beispiele in der Konsole eingetippt und mit der Enter-Taste bestätigt:
der Restwert kann auch berechnet werden:
Um ein bisschen experimentieren zu können, legen wir dafür erneut ein kleines Script an
Ein langer Dateiname, ich weiß. Möchte damit noch mal auf ein kleines Feature aufmerksam machen, das uns die Konsole bietet.
Wenn wir das Script nun im vi öffnen möchten, wissen wir ja, dass wir vi gefolgt von dem Dateinamen eingeben müssen. Um uns die Arbeit erleichtern zu können, tippen wir jetzt aber nur
ein und drücken einmal die TAB-Taste, welche sich links neben der Q-Taste befindet.
Der Dateiname wird vervollständigt und wir können unsere Eingabe mit 'Enter' bestätigen.
Oh, was Neues! )
Die Zeile, die mit dem #-Zeichen beginnt, leitet einen Kommentar ein, in den wir schreiben können, was wir möchten. Diese Zeile wird beim Ausführen ignoriert.
Wir addiren die zwei Zahlen und speichern sie in einer weiteren Variable mit dem Namen 'erg'.
Verwunderlich sind die komischen Fliegenschisse vor und nach dem expr-Befehl (der Berechnung).
Diese Zeichen bekommen wir, indem wir bei gedrückter "Shift"-Taste die "`"-Taste drücken (zu finden direkt rechts neben dem Fragezeichen.
Mit diesem Zeichen teilen wir dem Shellscript mit, dass wir ein Werkzeug aufrufen, mit dessen Ergebnis wir etwas machen wollen. In diesem Fall das Abspeichern in 'erg'.
Speichern wir das Script so und führen es aus, so werden wir folgende Ausgabe bekommen:
Bei so einer simplen Berechnung und wenn das Ergebnis im weiteren Code nicht weiter benötigt wird, kann man sich das Speichern in der 'erg'-Variable auch sparen und das Ergebnis direkt in der Ausgabe berechnen. Dies sieht dann so aus:
Einen weiteren Schritt machen wir jetzt noch.
Wir wollen Die Zahl, die zu 10 addiert werden soll, selber eingeben.
Das sieht dann wie folgt aus:
Wollen wir nun unsere Eingabe mit zu einer anderen Zahl als 10 addieren, so brauchen wir nur den Wert in der vierten Zeile ändern, da wir im echo-Befehl auf die Variable z1 Bezug nehmen.
-- Übergabe von Werten beim Scriptaufruf --
;-) Was wollen wir machen?
Es ist auch möglich mehrere Argumente zu übergeben und diese zu Mischen. Soll heißen:
sh Dateiname 10 Apfel ./bla.txt
Wir erinnern uns an das Script, das uns aufforderte unseren Namen einzugeben.
Wir modifizieren den Code, so dass wir den Namen beim Script-Aufruf mit übergeben.
in das Script kommt ein Zweizeiler:
Wie unschwer zu erkennen ist, wurde das übergebene Argument in '$1' hinterlegt.
Auf diese Weise haben wir die Möglichkeit an den Inhalt der übergebenen Argumente zu kommen.
Wichtig!
Bei der Übergabe des Namens, darf dieser kein Leerzeichen beinhalten, da dieser Name dann schon als zwei Argumente Interpretiert würde. Das müssen wir uns merken!
Ein Beispiel, bei dem wir unseren Namen, gefolgt von zwei Zahlen, die miteinander multipliziert werden, mit übergeben.
Dazu öffnen wir wieder '04_argumente' und passen dieses an die neuen Anforderungen an.
Um das Scipt aufzurufen geben wir nun folgendes in die Konsole ein
und bekommen dieses Ergebnis:
Den aufmerksamen Lesern, oder denen, wo statt der Berechnung nur eine Fehlermeldung kam, ist vielleicht aufgefallen, dass vor dem Mal-Zeichen ein Backslash steht.
Das ist notwendig, da es sich um ein spezielles Zeichen handelt (Meta-Zeichen für Dateinamen), das als solches benutzt werden soll.
Ein kleines Beispiel dazu. Der Text, der bei dem Echo-Befehl ausgegeben wird, steht in Anführungszeichen.
Jetzt wollen wir, dass der Name, den wir mit übergeben, bei der Ausgabe auch in Anführungszeichen steht und ändern desshalb unser Script noch ein ganz klein wenig ab.
Wir schreiben jetzt sowohl vor als auch hinter die Variable $1 die beiden Zeichen \". Dieser ominöse Backslash verhindert, dass der Echo-Befehl denkt, dass bei den Anführungszeichen die Ausgabe schon zu Ende sei. Das gleiche gilt hinter der Variable.
Wenn wir alles richtig gemacht haben, erscheint, wenn wir das Script wie eben mit Hans, 3, 5 aufrufen:
Ein paar weitere Erläuterungen!
;-) Was wollen wir machen?
Eine if-Abfrage kann immer nur einen von maximal zwei Zuständen haben.
Trifft die Bedingung zu, ist der Rückgabewert 'wahr'.
Trifft die Bedingung nicht zu, ist der Rückgabewert 'false'.
Da wir aber programmieren und uns somit im Englischen bewegen... true und false!
Als erstes wollen wir aber wissen, ob 10 größer ist als 8.
Zugegeben, es scheint sich um eine recht simple, wenn nicht sogar dämliche, Fragestellung zu handeln. Dennoch eignen sich derartige einfachen Beispiele die if-Abfrage näher zu bringen.
Um jetzt die Datei anzulegen ist es Zeit eine weitere Möglichkeit kenn zu lernen, eine Datei anzulegen und sich den touch-Befehl zu sparen.
Wir tippen vi gefolgt von dem gewünschten Script-Namen ein und bestätigen mit der Enter-Taste.
Der vi öffnet sich, hat aber die Datei noch nicht angelegt. Dies passiert erst, wenn wir den Code gleich geschrieben haben und wie gewohnt mit unserem Zup-Zup-Befehl (Shift + Z Z) den Editor verlassen.
Der Code, den wir jetzt eingeben werden, überprüft den Wert aus Variable 1 mit dem aus Variable 2 und sagt uns, wenn der Wert größer ist.
Der Aufbau ist vom Prinzip her simpel: Wenn, dann tue dies, ansonsten das!
Man kann aber viele Fehler machen. Sowohl bei der Syntax (also wie man die Abfrage tippen muss), als auch bei der Logik kann man ganz schnell ungewollte und die wirrsten Ergebnisse bekommen.
Bei der Syntax ist zu beachten, dass vor und hinter jedem "[" und "]" ein Leerzeichen steht, da es sonst zu ungewollten Fehlern kommt.
Desweiteren ist zu beachten, dass unter dem "if" ein "then" steht, welches nicht in der gleichen Zeile wie die Abfrage selber stehen darf.
Eine ganz wichtige Sache ist das Einrücken von Zeilen. Ich empfehle jeweils immer zwei Leerzeichen. Das sollten wir uns schnellst möglichst angewöhnen und auch einhalten. Wenn wir später 5 bis 10 Schleifen und Abfragen verschachteln, würden wir ansonsten durch deren Aufbau nicht mehr durchsteigen.
Auch wenn Sie den Sinn nicht auf Anhieb verstehen, lege ich Ihnen trotzdem ans Herz den Ratschlag zu befolgen.
Abgeschlossen wird die Abfrage mit "fi" (if umgedreht). Ob das nun so schön ist, darüber lässt sich streiten. Es ist einfach so.
Ist $z1 größer als $z2, werden alle Befehle nach dem 'then' abgearbeitet. Ist $z1 genau so groß wie $z2 oder kleiner, wird der else-Zweig verarbeitet.
Um nun sicher zu wissen, ob die $z2 auch wirklich kleiner (nennt man: echt kleiner) ist, müssen wir eine weitere Abfrage in den else-Zweig einbinden. Wir sprechen dann von einer Verschachtelung.
Dazu kommen wir noch einmal, wenn wir es brauchen.
Erst mal vergleichen wir jetzt zwei Strings (Zeichenfolgen) in einem weiteren Script miteinander.
Beim Script-Aufruf sollen zwei Werte mit übergeben werden (wie das geht, wissen wir ja bereits), die dann verglichen werden.
Am besten, wir probieren ein wenig mit dem Script herum. Rufen es ein paar mal mit unterschiedlichen Werten auf.
Bsp.:
Auffällig sind die zwei Gleichheitszeichen.
Wann verwenden wir ein '=' und wann '=='?
Wir speichern die Zeichenfolge 'blubb' in der Variable $vergl. Anschließend vergleichen wir den Inhalt aus dieser Variable mit dem beim Aufruf ersten mit übergebenen String.
Nur wenn diese beiden Strings identisch sind, wird der else-Zweig verarbeitet.
Ein weiteres Anwendungsbeispiel.
In Kapitel 04 haben wir gelernt, wie wir Argumente beim Scriptaufruf übergeben. Jetzt schreiben wir ein kleines Shellscript, das überprüft, ob überhaupt ein Argument (in diesem Beispiel ein Name) übergeben wurde und falls nicht, den User auf diesen Missstand aufmerksam macht.
Wir erinnern uns, dass in '$#' die Anzahl der übergebenen Argumente steht und wir somit einfach ihren Wert auf Null prüfen können um zu wissen, dass kein Argument übergeben wurde.
Ist der Wert nicht 0, wird der else-Zweig ausgeführt und in unserem Beispiel der Satz "Mein Name ist xyz" ausgegeben.
Eine Anmerkung noch!
Nur weil wir hier nur echo-Befehle in den Abfragen benutzt haben, bedeutet das nicht, dass nichts Anderes möglich sei. Die Möglichkeiten sind da nahezu unbegrenzt, wie wir im Weiteren auch noch sehen werden.
-- test testen --
;-) Was wollen wir machen?
Unix bietet uns ein Werkzeug mit dem Namen 'test'. Dies ist auch der Grund, warum ich davon abrate, einer Datei den Dateinamen 'test' zu geben!
Mit test lassen sich die verschiedensten Dinge abprüfen. Einige von den vielen vielen Möglichkeiten schauen wir uns mal genauer an.
Wir haben es eben sogar schon benutzt! An Stelle von
hätten wir auch (aber ohne die eckigen Klammern)
schreiben können. Beide Zeilen sind gleichbedeutend und haben, wenn die beiden Werte unterschiedlich sind, den Rückgabewert 'true', da die Bedingung, dass sie ungleich sind, zutrifft.
Um uns mal einen Überblick zu verschaffen, welche Möglichkeiten uns das Werkzeug so gibt, geben wir in der Konsole mal
ein. Mit dem Bestätigen durch die Enter-Taste, wird die Hilfe dieses Werkzeuges aufgerufen. Mit den Pfeiltasten können wir rauf und runter scrollen und verlassen können wir die Hilfe durch das Drücken der 'q'-Taste (q = quit).
Wie wir sehen, bietet test uns jede Menge Möglichkeiten.
Also, los geht's...
Wir fordern den Benutzer auf seine Lieblings-Obstsorte einzugeben und prüfen anschließend ab, ob er das auch getan hat.
In dem Manual von test haben wir eben nachgelesen, dass '-z' prüft, ob eine Zeichenfolge die Länge 0 hat.
Ist dies der Fall, wird true, ansonsten false zurückgegeben.
Probieren wir beides aus. Wir starten das Script
und werden nun aufgefordert eine Obstsorte einzugeben. Drücken wir jetzt ohne eine Eingabe die Enter-Taste, wird test den Rückgabewert true haben und es wird auf dem Bildschirm erscheinen, dass wir keine Obstsorte angegeben haben.
Geben wir hingegen beispielsweise 'Apfel' ein, ist der Rückgabewert von test false, da die Zeichenlänge ja nicht 0 ist, und somit wird der else-Zweig bearbeitet.
In der Manual zu test haben wir ja auch gelesen, dass sich dieses Werkzeug wunderbar dazu eignet um Dinge rund um Dateien abzufragen.
Wir werden uns an dieser Stelle noch nicht darum kümmern, sondern kommen an gegebender Stelle darauf zurück.
-- Schleifen --
;-) Was wollen wir machen?
Neuer Abschnitt, also erst mal eine neue Datei:
Als Ergebnis unsere ersten Schleife wollen wir dieses Ergebnis bekommen.
Solange x <= 10, addiere 1 zu x.
Wir wollen mit der 1 anfangen. Aus diesem Grund weisen wir der Variable $x gleich am Anfang den Wert 1 zu.
Wir erinnern uns, dass bei einer Wertzuweisung das $-Zeichen weggelassen werden muss.
Jetzt geht es in die Schleife. Eröffnet wird sie mit "while" und den eckigen Klammern. Auch hier ist es wieder wichtig, dass vor und nach den Klammern Leerzeichen sind.
Was wir oben (in den eckigen Klammern) sehen, ist die Bedingung. Wir überprüfen, ob $x kleiner oder gleich ist, dafür sorgt "-le", was für "less or equal" steht und eine Option von test ist, welches hier wieder zum Einsatz kommt.
Nach der Bedingung folgt das Schlüsselwort "do", welches den auszuführenden Teil einleitet.
Der Part, der während des Schleifendurchlaufs ausgeführt werden soll, sollte wieder unbedingt eingerückt werden (auch hier empfehle ich zwei Leerzeichen).
Was tut unsere Schleife denn da überhaupt?
Erst kümmern wir uns um die Ausgabe: x = 1, x = 2, ...
Danach wird x mit dem Werkzeug 'expr' das wir ja schon kennen, um einen erhöht. Das ist ganz wichtig, da die Schleife sonst NIE enden würde, nur der Rechner irgendwann alle Viere von sich streckt und neugestartet werden müsste.
Wenn wir allerdings doch mal in so einer Endlosschleife hängen, können wir diese, und auch jeden anderen Programm-Ablauf, mit der Tastenkombination STRG+C (oder CTRL+C) abwürgen.
Der Dateiname unseres Scriptes hat es uns eigentlich schon verraten,... wir werden noch eine weitere Schleife basteln. Da es sich um eine Schleife handelt, die sich von while-Schleife unterscheidet, werden wir ihr eine neue Datei gönnen.
Welche Schleife wann zum Einsatz kommt, das ist immer so eine Sache. Manche verstehen das nie und oft sind auch beide möglich, aber die eine halt einfach schöner!
Man könnte sagen, die for-Schleife kommt zum Einsatz, wenn die Anzahl der Durchläufe bekannt ist.
Wir dürfen nicht verzweifeln, wenn wir bei unseren ersten Versuchen die falsche Schleife anwenden, zum Ziel kommt man oft trotzdem.
Jetzt aber los! Wir wollen ein Script, dem beim Aufruf mehrere Variablen übergeben werden können.
Eben haben wir gesagt, dass sich eine for-Schleife eignet, wenn wir wissen, wie viele Durchläufe wir haben werden.
Wir erinnern uns, dass wir mit $# abprüfen können, wie viele Argumente beim Scriptaufruf übergeben wurden, also wissen wir, wie oft die Schleife durchlaufen werden muss, um alle Argumente wieder auf dem Bildschirm auszugeben.
Bei folgendem Scriptaufruf
erhalten wir diese Ausgabe auf dem Bildschirm
Erst werden alle Argumente angezeigt, dafür sorgt '$*' und danach wird die Schleife durchlaufen und jedes Argument einzeln angesprochen und ausgegeben.
An Stelle der Ausgabe, kann natürlich auch jede andere Aktion mit dem Argument gemacht werden!
-- Erstes kleines Programm --
;-) Was wollen wir machen?
Doch erst mal ein paar Vorbereitungen.
Legen wir erst mal eine Namensliste an. Womit? Na klar, mit dem vi!!
und füllen die Liste mit ein paar Datensätzen
Machen wir erst eine Trockenübung.
Nachdem wir die obrige Namensliste erstellt und den vi wieder verlassen haben, versuchen wir uns einmal an folgendem Befehl:
Das Ergebnis wird sein:
Damit ist eigentlich schon geklärt, welche Aufgabe das Werkzeug grep haben wird.
Nun aber zu unserem Programm. Fangen wir ganz einfach und unkompliziert an.
(Die Dateinamen werden immer länger - ich erinnere noch mal an die nette Möglichkeit der Autovervollständigung durch die Tab-Taste!!)
Beim Aufruf braucht man jetzt nur nach dem Scriptnamen noch ein "na" zu tippen und einmal die Tab-Taste zu betätigen. Ein weiterer Druck auf 'Enter' startet das Script.
Wir werden aufgefordert einen Suchstring einzugeben. Tippen wir zum Test wieder 'Ellen' ein, wird wieder 'Ellen Bogen' ausgegeben.
Gäbe es noch einen weiteren Namen, der 'Ellen' enthält, würden beide Suchergebnisse untereinander ausgegeben.
Folgendes steht auf dem Programmplan:
Das war doch ein Klaks für uns! )
Prüfen wir nun ab, ob überhaupt ein Argument mit übergeben wurde.
Eine Variable hat uns ihre Hilfe angeboten und die nehmen wir gerne an.
In dieser Variable, mit dem Namen 'doit', werden wir eine 0 schreiben, wenn kein, und eine 1, wenn doch ein Argument übergeben wurde.
Und zwar prüfen wir das noch bevor wir unseren Suchstring eingeben, da das ja unnötig wäre, wenn eh keine Datei zum drin suchen angegeben wurde.
Jetzt wird nur nach einem String gefragt und dieser zum Suchen benutzt, wenn auch ein Argument beim Script-Aufruf übergeben wurde.
Was aber, wenn man statt "namenliste.txt" einfach eine Zahl, oder anderen Unsinn, angibt?
Dumm gelaufen! Und darum werden wir die Abfrage erweitern, dass zusätzlich gefragt wird, ob das Argument eine lesbare Datei ist. Das Werkzeug test wird uns behilflich sein und aus der Manual wissen wir, dass '-r' genau das bei einer Datei abprüft, was wir wissen wollen.
Wenn also überhaupt ein Argument übergeben wurde, dann prüfen wir, ob es sich um eine existierende und lesbare Datei handelt und nur dann geht es weiter im Programm:
Das Ergebnis der Bedingungen wird auch hier wieder in der Variable 'doit' festgehalten.
Jetzt sehen wir auch, warum es sich gelohnt hat, die Abfrage nicht direkt in die unterste if-Abfrage einzubauen, sondern sie gesondert zu behandeln. Es würde gehen, aber so ist es übersichtlicher und kompfortabler und vor allem leichter erweiterbar, wie im nächsten Kapitel!
Bevor wir unser Script noch erweitern, muss es erst noch getestet werden.
Um es auch an einer nicht lesbaren Datei zu testen, werden wir diese jetzt anlegen und das Leserecht nehmen.
Dieser gerade angelegten Datei nehmen wir jetzt das Leserecht:
Wenn wir nun diese Datei, statt der 'namenliste.txt' beim Scriptaufruf angeben, werden wir die Meldung bekommen, dass diese Datei nicht existiert, oder nicht lesbar ist.
;-) Was wollen wir machen?
Der Befehl dazu ist 'cp' gefolgt von der zu kopierenden Datei und dem Zielnamen:
(ich erinnere noch mal an die Möglichkeit der Autovervollständigung der Datei-Namen durch die TAB-Taste!!)
Wir befinden uns jetzt im vi und können uns ans Werk machen.
Aha - und was geschieht da nun?
In der ersten If-Abfrage prüfen wir, ob denn überhaupt ein Argument, also eine Datei, übergeben wurde. Ist dies nicht der Fall, kommt eine entsprechende Meldung und unser Script ist schon am Ende.
Wurde aber doch mindestens eine Datei angegeben, so wird im nächsten Schritt nach dem zu suchenden String gefragt. Wir geben diesen ein und es geht in die For-Schleife (auch Zählschleife genannt). Diese arbeitet nun alle übergebenen Dateien ab. Wenn nur eine Datei übergeben wurde, wird auch nur eine abgearbeitet. Bei zwei, hat die Schleife zwei Durchläufe.
Das wollen wir doch mal testen.
Wir haben ja bereits die Datei "namenliste.txt". Kopieren wir diese doch einfach...
Wenn wir wollen können wir den Inhalt jetzt noch abändern, ist aber für den ersten Testdurchlauf nicht unbedingt notwendig.
Wie rufen wir unser Script denn jetzt mit zwei Argumenten auf? Nichts leichter als das:
Die zwei Dateien einfach mit Leerzeichen trennen. So können noch weitere Dateien angehängt werden.
Fertig!
-- 6 aus 49 --
;-) Was wollen wir machen?
Und warum? Na ja. Zum Einen, weil das in fast jedes Beginner-Tut gehört und weil ich danach gefragt wurde.
Kein Müdigkeit vortäuschen...
... und wir tippen:
Weil es mit der Zeit jetzt ein wenig unübersichtlich wird, werde ich ab jetzt, wo es sich anbietet, statt des Kommentars eine Zahl anfügen und unter dem Quellcode erläutern, was an Stelle des Kommentars dort steht.
Das gehört geändert.
Und genau darum kümmern wir uns jetzt.
Da wir geschachtelte Schleifen mögen, werden wir jetzt einfach eine weitere Schleife einbauen, die solange eine neue Zufallszahl anfordert, bis eine gefunden wurde, die noch nicht in der 'lotto_temp' steht.
Neue / geänderte Zeilen sind wieder fett abgebildet.
Direkt nach dem Anlegen der 'lotto_temp' holen wir uns die erste Zufallszahl, damit 'rnd' nicht leer steht wenn es gleich in die inner While-Bedingung geht, welche mit dem Werkzeug 'grep' abfragt, wie oft der in 'rnd' gespeicherte Wert in der temporären Datei vorkommt.
Das '-gt' steht für 'greater than / größer als' (nicht größer/gleich als!!)
So wird so lange eine neue Zufallszahl angefordert, bis die Anzahl = 0 ist und wir haben fortan keine Duplikate mehr.
Viel Glück bei der nächsten Ziehung!
-- Lock-Screen --
;-) Was wollen wir machen?
Jetzt nicht gleich das Browser-Fenster schließen! Klingt komplizierter als es ist.
Das Passwort soll beim Aufruf des Scriptes festgelegt werden.
Nun wäre es strategisch unpraktisch, wenn das PW beim Festlegen lesbar auf dem erscheinen würde.
Deshalb schauen wir mal, wie wir das umgehen können. Das Werkzeig 'stty' hilft uns.
Es ermöglicht es die Eingabe unsichtbar geschehen zu lassen.
Ein kleines Beispiel:
Wenn wir das Script nun ausführen, werden wir aufgefordert unser Passwort festzulegen.
Wir stellen fest, dass sich der Cursor sich nicht von der Stelle bewegt. So kann niemand, der einem über die Schulter guckt, die Zeichenanzahl unseres PWs erkennen.
Nachdem wir unsere Eingabe, wie gewohnt, mit ENTER bestätigen, wird unser PW ausgegeben.
Sicher, das ist sinnfrei! Aber es handelt sich hier ja nur um ein Beispiel.
Löschen wir die unteren beiden Zeilen (im vi in die entsprechende Zeile gehen und zwei mal die 'd'-Taste drücken).
Oh! Was ist das denn alles?
In der Variable 'MATCH' erfassen wir später die PW-Eingaben.
Wir werden unserem Script einen kleinen Leckerbissen verpassen. Nach jeder falschen Eingabe, wird die Wartezeit auf die nächste Eingabe verdoppelt.
Den Startwert von 1 weisen wir der Variable 'DELAY' zu.
Jetzt kümmern wir uns um die Schleifenbedingung:
--> Solange unser Wert in 'MATCH' nicht mit dem Wert in 'CODE' übereinstimmt...
Was packen wir jetzt in den Schleifenkörper?
Jetzt schustern wir die anderen Sachen noch davor und ein 'echo' danach und wir können zum ersten Test antreten
Den 'sleep'-Befehl nutzen wir zum Warten. Beim ersten Mal genau eine Sekunde. Beim zweiten Mal zwei, beim dritten Mal 4,... 8,... 16,...
Dafür zuständig ist die Zeile
Dem 'echo'-Befehl der darauf folgende 'read'-Anweisung bedarf es wohl keiner weiteren Erläuterung, oder?
Na gut, noch mal ganz kurz: Der Benutzer wird aufgefordert ein Passwort einzugeben und seine Eingabe wird der Variable 'MATCH' zugewiesen.
Rufen wir das Script mal auf:
Wir werden aufgefordert ein Passwort festzulegen.
Geben wir das richtige ein, können wir weiterarbeiten.
Wir haben bei unseren Schleifen-Scripten die Möglichkeit kennen gelernt, mit der Tastenkombination "STRG + C" einen Ablauf abzubrechen.
Oh, was ist das? Das geht hier ja auch - sehr ungünstig!
Also müssen wir noch mal ran.
Eine andere,... nennen wir es erst mal Oberfläche, erlaubt es uns die Tastenkombination zu unterbinden.
Den Aufruf dieser anderen Bash erreichen wir wie folgt mit dem Werkzeug 'trap'
Die in unser vorhandenes Script einzufügende Zeile ist fett gedruckt
-- Idealgewicht --
;-) Was wollen wir machen?
Die Berechnung lautet:
Vom Benutzer benötigen wir die Eingabe von Körpergröße (in cm) und das Körpergewicht (in kg)
Jetzt können wir uns an die Berechnung begeben.
Als erstes ziehen wir die 100 von der Körpergröße ab und speichern das Ergebnis schon mal in der Variable für das Idealgewicht.
Zur Berechnung benutzen wir wieder unser Werkzeug 'expr' - klar, oder?
Der nächste Schritt besteht darin mit 0,9 zu multiplizieren.
Ach, ist gar kein Problem. Als mathematisch versierte Scripter erkennen wir sofort folgenden Lösungsweg:
Wir multiplizieren mit 9 und dividieren anschließend durch 10.
Kommen wir zur Ausgabe:
Jetzt wäre es natürlich noch schön, wenn wir gleich mit ausgeben, wie viel Über-, bzw. Untergewicht der Benutzer hat.
Dazu berechnen wir im ersten Schritt die Differenz
Jetzt schustern wir die anderen Sachen noch davor und ein 'echo' danach und wir können zum ersten Test antreten.
Was passiert da so weit?
Es wird geprüft, ob die Differenz echt größer als 0 ist.
Ist dies nicht der Fall, geht es in den Else-Zweig, den wir jetzt füllen
Die Abfrage müsste sich von selbst erklären. Wir prüfen auf echt kleiner. Ist das der Fall, ist die Person untergewichtig.
Trifft das nicht zu, kann nur noch ein Fall eintreten, der Else-Zweig wird aufgerufen.
Rufen wir das Script mal auf:
Wir werden aufgefordert, unsere Köfpergröße einzugeben, so wie unser Gewicht und erhalten das ernüchternde Ergebnis...
Das war es für's erste...
Über Verbesserungsvorschläge oder Bemerkungen anderer Art würde ich mich freuen (besonders wenn es jemandem gefallen hat )
MfG Kryp
- Erste Ausgabe
- Benutzereingaben
- Ein wenig rechnen
- Argumente
- If-Abfragen
- test testen
- Schleifen
- Erstes kleines Programm
- 6 aus 49
- Lock-Screen
- Idealgewicht
Shell-Scripts (Kommandoprozeduren) können mit Batch-Dateien unter MS-Dos verglichen werden, sind jedoch wesentlich leistungsfähiger.
Ein Shell-Script ist eine Textdatei, in der Kommandos gespeichert sind. Es stellt selbst ein Kommando dar, da es wie ein Systemkommando, auch mit Parametern, aufgerufen werden kann. Shell-Scripts dienen der Arbeitserleichterung und (nach ausreichenden Tests) der Erhöhung der Zuverlässigkeit, da sie gestatten, häufig gebrauchte Sequenzen von Kommandos zusammenzufassen.
Ein Anwendungsbeispiel wäre das nächtliche Kopieren von wichtigen Daten auf einen anderen Rechner im Netzwerk, oder das bearbeiten (z.B. umbenennen oder Rechte setzen) vieler Datein auf einen Schlag.
Es gibt unzählige weitere Anwendungsmöglichkeiten.
Voraussetzungen
Um dieses Tutorial durchführen zu können, benötigen wir Zugang zu einem Unix-Rechner (Linux, OS X).
Stellt dies kein Problem dar sollten wir und mit der Navigation in der Verzeichnis-Struktur des Systems schon einmal befasst haben. Sprich: das wechseln in ein anderes Verzeichnis, wissen, was das Home-Verzeichnis ist und wie wir da wieder hin kommen.
Das ist aber auch schon alles, was wir an Voraussetzungen benötigen.
Was bringt mir dieses Tut?
Am Ende dieses Tutorials haben wir einen kleinen Überblick über Standard-Kontrollstrukturen und Grund-Befehle, die in fast jedem Shell-Script vorkommen.
Wir versuchen einen Wissensstand zu erlangen, so dass wir in Zukunft eine Problemstellung erkennen und wissen, wie wir an die Lösung heran gehen.
Dazu gehört auch das Wissen, es gibt unzählige weitere Möglichkeiten / Tools (einige werden wir kennen lernen), die wir zur Lösung unseres Problems verwenden können.
Kurz: wir eignen uns hier die Basics an...
Fangen wir langsam an...
-- Erste Ausgabe --
;-) Was wollen wir machen?
- wir wollen, weil das einfach immer so ist, einfach mal mit der "Hallo Welt"-Ausgabe beginnen )
Wir öffnen die Konsole (Terminal) und legen am besten erst mal einen Ordner an, in dem wir alle unsere Scripte ablegen. Nennen wir den Ordner beispielsweise "shellscripte":
(alles was ab jetzt in den Code-Bereichen steht, spielt sich im Terminal / in der Konsole ab!)
Code:
mkdir shellscripte
Code:
cd shellscripte
Zuerst aber legen wir die Datei mit dem Namen "01_ausgabe" an
Code:
touch 01_ausgabe
Jetzt öffnen wir mit dem vi-Editor die ebend angelegte Datei
Code:
vi 01_ausgabe
Code:
echo "Hallo Welt"
Jetzt wollen wir das Script speichern und den vi verlassen. Dazu drücken wir bei gedrückter Shift-Taste zwei mal die Z-Taste drücken.
(wesentlich bekannter ist die Variante an dieser Stelle :wq einzugeben und mit Enter zu bestätigen. Jeder so wie er es mag... )
Jetzt befinden wir uns wieder direkt in der Konsole und können unser Script testen
Code:
sh 01_ausgabe
-- Benutzereingaben --
;-) Was wollen wir machen?
- da man irgendwann immer an dem Punkt ankommt, wo eine Eingabe unbedingt erforderlich ist, werden wir uns jetzt mal darum kümmern
Legen wir das script an und öffnen es zum Bearbeiten mit dem vi.
Code:
touch 02_eingaben
vi 02_eingaben
Code:
clear
echo -n "Bitte geben Sie Ihren Namen ein: "
read name
echo ""
echo "Mein Name ist $name."
Mit dem Schlüsselwort "clear" wird die Konsole 'aufgeräumt', sprich: der Inhalt gelöscht. Werden wir gleich sehen, wenn wir das Script ausführen.
Wir wollen uns gleich von Anfang an angewöhnen, die Übersicht zu behalten. Darum auch nach "clear" eine Leerzeile.
Was "echo" und bringt, wissen wir ja bereits. Neu ist hier nur das Argument '-n'. Mit diesem Argument geben wir an, dass der Cursor am Ende der Ausgabe stehen bleiben soll, so dass wir unseren Namen in der gleichen Zeile eingeben müssen.
Das Werkzeug "read" nimmt dann unseren eingegebenen Namen entgegen und speichert ihn in der Variable 'name'.
Mit dem nun folgenden "echo"-Befehl fügen wir einfach nur eine Leerzeile bei der späteren Ausgabe ein.
Nun kommen wir zur eigentlichen Ausgabe.
Gar nicht schwer! Wir nehmen die eben gefüllte Variable 'name' mit in unsere Ausgabe auf.
Uns fällt auf, dass dort plötzlich ein Doller-Zeichen vorangestellt ist. Immer wenn wir an den Wert einer Variable wollen, also den Inhalt auslesen möchten, schreiben wir ein $-Zeichen vor die Variable.
Speichern wir wieder mit gedrückter Shift-Taste und zweimaligen drücken der z-Taste und führen das Script aus.
Code:
sh 02_eingaben
Code:
Bitte geben Sie Ihren Namen ein: Gerrit
Mein Name ist Gerrit.
Dazu legen wir keine neue Datei an. Wir erweitern das Script von eben, also öffnen wir es mit vi, indem wir das zu öffnende Script direkt als Argument mit übergeben.
Code:
vi 02_eingaben
Code:
clear
echo -n "Bitte geben Sie Ihren Namen ein: "
read name
[B]echo -n "und wie alt sind Sie? "
read alter[/B]
echo ""
echo "Mein Name ist $name [B]und ich bin $alter Jahre alt."
echo ""[/B]
Rufen wir das Script jetzt auf,
Code:
sh 02_eingaben
Ich denke, das Prinzip ist klar )
-- Ein wenig rechnen --
;-) Was wollen wir machen?
- wir nehmen ein weiteres Werkzeug mit dem Namen "expr" aus der Unix-Werkzeugkiste und werden uns mal anschauen, was damit so möglich ist
(alle Funktionen können nicht erklärt werden, da das in einem Buch enden würde - für weitere informationen geben Sie in der Konsole "man expr" ein oder )
"expr" ist ein mächtiges Rechenwerkzeug. Ein paar Beispiele in der Konsole eingetippt und mit der Enter-Taste bestätigt:
Code:
expr 2 + 5
Code:
expr 100 - 19
Code:
expr 10 % 3
Code:
touch 03_ein_wenig_rechnen
Wenn wir das Script nun im vi öffnen möchten, wissen wir ja, dass wir vi gefolgt von dem Dateinamen eingeben müssen. Um uns die Arbeit erleichtern zu können, tippen wir jetzt aber nur
Code:
vi 03
Der Dateiname wird vervollständigt und wir können unsere Eingabe mit 'Enter' bestätigen.
Code:
clear
# Variablen mit Werten fuellen
z1=10
z2=11
erg=`expr $z1 + $z2`
echo "$z1 + $z2 ist $erg!"
echo ""
Die Zeile, die mit dem #-Zeichen beginnt, leitet einen Kommentar ein, in den wir schreiben können, was wir möchten. Diese Zeile wird beim Ausführen ignoriert.
Wir addiren die zwei Zahlen und speichern sie in einer weiteren Variable mit dem Namen 'erg'.
Verwunderlich sind die komischen Fliegenschisse vor und nach dem expr-Befehl (der Berechnung).
Diese Zeichen bekommen wir, indem wir bei gedrückter "Shift"-Taste die "`"-Taste drücken (zu finden direkt rechts neben dem Fragezeichen.
Mit diesem Zeichen teilen wir dem Shellscript mit, dass wir ein Werkzeug aufrufen, mit dessen Ergebnis wir etwas machen wollen. In diesem Fall das Abspeichern in 'erg'.
Speichern wir das Script so und führen es aus, so werden wir folgende Ausgabe bekommen:
Code:
10 + 11 ist 21!
Code:
clear
# Variablen mit Werten fuellen
z1=10
z2=11
echo "$z1 + $z2 ist `[B]expr $z1 + $z2[/B]`!"
echo ""
Wir wollen Die Zahl, die zu 10 addiert werden soll, selber eingeben.
Das sieht dann wie folgt aus:
Code:
clear
# Variablen mit Werten fuellen
z1=10
[B]echo -n "Welche Zahl wollen Sie zu $z1 addieren: "
read z2
echo ""[/B]
echo "$z1 + $z2 ist `expr $z1 + $z2`!"
echo ""
-- Übergabe von Werten beim Scriptaufruf --
;-) Was wollen wir machen?
- ganz wichtig für das effiziente Arbeiten mit Shellscripten ist das Übergeben von Argumenten
Es ist auch möglich mehrere Argumente zu übergeben und diese zu Mischen. Soll heißen:
sh Dateiname 10 Apfel ./bla.txt
Wir erinnern uns an das Script, das uns aufforderte unseren Namen einzugeben.
Wir modifizieren den Code, so dass wir den Namen beim Script-Aufruf mit übergeben.
Code:
touch 04_argumente
vi 04_argumente
Code:
clear
echo "Mein Name ist $1."
Auf diese Weise haben wir die Möglichkeit an den Inhalt der übergebenen Argumente zu kommen.
Wichtig!
Bei der Übergabe des Namens, darf dieser kein Leerzeichen beinhalten, da dieser Name dann schon als zwei Argumente Interpretiert würde. Das müssen wir uns merken!
Ein Beispiel, bei dem wir unseren Namen, gefolgt von zwei Zahlen, die miteinander multipliziert werden, mit übergeben.
Dazu öffnen wir wieder '04_argumente' und passen dieses an die neuen Anforderungen an.
Code:
clear
echo "Hallo $1. Das Ergebnis ist `expr $2 \* $3`."
echo ""
Code:
sh 04_argumente Hans 5 3
Code:
Hallo Hans. Das Ergebnis ist 15.
Das ist notwendig, da es sich um ein spezielles Zeichen handelt (Meta-Zeichen für Dateinamen), das als solches benutzt werden soll.
Ein kleines Beispiel dazu. Der Text, der bei dem Echo-Befehl ausgegeben wird, steht in Anführungszeichen.
Jetzt wollen wir, dass der Name, den wir mit übergeben, bei der Ausgabe auch in Anführungszeichen steht und ändern desshalb unser Script noch ein ganz klein wenig ab.
Code:
clear
echo "Hallo \"$1\". Das Ergebnis ist `expr $2 \* $3`."
echo ""
Wenn wir alles richtig gemacht haben, erscheint, wenn wir das Script wie eben mit Hans, 3, 5 aufrufen:
Code:
Hallo "Hans". Das Ergebnis ist 15.
- der ein oder andere wird sich vielleicht gefragt haben, warum das erste Argument mit $1 angesprochen wird und ob $0 ggf. auch eine Verwendung hat.
Richtig! $0 repräsentiert den Namen des aktuellen Shellscripts.
Die Argumente finden sich in den Variablen $1 ... $9 wieder.
An alle Argumente auf einen Schlag kommen wir mit $*
Es gibt noch ein paar weitere Befehle, aber die sollen uns jetzt noch nicht interessieren.
Einzig $# ist noch interessant, um die Anzahl der übergebenen Argumente zu ermitteln.
;-) Was wollen wir machen?
- um Kontrollstrukturen kommt kein Programmierer drum herum. Auch nicht, wenn es sich um einfache Shellscripte handelt.
Aus diesem Grund fangen wir ganz leicht mit der Wenn-Dann-Abfrage an.
Eine if-Abfrage kann immer nur einen von maximal zwei Zuständen haben.
Trifft die Bedingung zu, ist der Rückgabewert 'wahr'.
Trifft die Bedingung nicht zu, ist der Rückgabewert 'false'.
Da wir aber programmieren und uns somit im Englischen bewegen... true und false!
Als erstes wollen wir aber wissen, ob 10 größer ist als 8.
Zugegeben, es scheint sich um eine recht simple, wenn nicht sogar dämliche, Fragestellung zu handeln. Dennoch eignen sich derartige einfachen Beispiele die if-Abfrage näher zu bringen.
Um jetzt die Datei anzulegen ist es Zeit eine weitere Möglichkeit kenn zu lernen, eine Datei anzulegen und sich den touch-Befehl zu sparen.
Wir tippen vi gefolgt von dem gewünschten Script-Namen ein und bestätigen mit der Enter-Taste.
Code:
vi 05_zahlen_vergleichen
Der Code, den wir jetzt eingeben werden, überprüft den Wert aus Variable 1 mit dem aus Variable 2 und sagt uns, wenn der Wert größer ist.
Code:
clear
z1=10
z2=8
if [ $z1 > $z2 ]
then[INDENT]echo "$z1 ist groesser als $z2."[/INDENT]else[INDENT]echo "$z1 ist kleiner oder gleich $z2."[/INDENT]fi
echo ""
Man kann aber viele Fehler machen. Sowohl bei der Syntax (also wie man die Abfrage tippen muss), als auch bei der Logik kann man ganz schnell ungewollte und die wirrsten Ergebnisse bekommen.
Bei der Syntax ist zu beachten, dass vor und hinter jedem "[" und "]" ein Leerzeichen steht, da es sonst zu ungewollten Fehlern kommt.
Desweiteren ist zu beachten, dass unter dem "if" ein "then" steht, welches nicht in der gleichen Zeile wie die Abfrage selber stehen darf.
Eine ganz wichtige Sache ist das Einrücken von Zeilen. Ich empfehle jeweils immer zwei Leerzeichen. Das sollten wir uns schnellst möglichst angewöhnen und auch einhalten. Wenn wir später 5 bis 10 Schleifen und Abfragen verschachteln, würden wir ansonsten durch deren Aufbau nicht mehr durchsteigen.
Auch wenn Sie den Sinn nicht auf Anhieb verstehen, lege ich Ihnen trotzdem ans Herz den Ratschlag zu befolgen.
Abgeschlossen wird die Abfrage mit "fi" (if umgedreht). Ob das nun so schön ist, darüber lässt sich streiten. Es ist einfach so.
Ist $z1 größer als $z2, werden alle Befehle nach dem 'then' abgearbeitet. Ist $z1 genau so groß wie $z2 oder kleiner, wird der else-Zweig verarbeitet.
Um nun sicher zu wissen, ob die $z2 auch wirklich kleiner (nennt man: echt kleiner) ist, müssen wir eine weitere Abfrage in den else-Zweig einbinden. Wir sprechen dann von einer Verschachtelung.
Dazu kommen wir noch einmal, wenn wir es brauchen.
Erst mal vergleichen wir jetzt zwei Strings (Zeichenfolgen) in einem weiteren Script miteinander.
Code:
vi 05_strings_vergleichen
Code:
clear
if [ $1 == $2 ]
then[INDENT]echo "Die beiden Zeichenfolgen sind identisch."[/INDENT]else[INDENT]echo "$1 unterscheidet sich von $2!"[/INDENT]fi
echo ""
Bsp.:
Code:
sh 05_strings_vergleichen Apfel Birne
Wann verwenden wir ein '=' und wann '=='?
- '=' verwenden wir bei einer Wertzuweisung.
Bsp: wert1=10 - '==' wird verwendet, wenn der Inhalt zweier Werte auf Gleichheit geprüft wird.
Tipp: Ungleich würde man mit '!=' prüfen!
Code:
clear
if [ $1 == $2 ]
then[INDENT]echo "Die beiden Zeichenfolgen sind identisch."[/INDENT]else[INDENT]echo "$1 unterscheidet sich von $2!"[/INDENT]fi
echo ""
<b># Auf ungleich prüfen
vergl=blubb
if [ $1 != $2 ]
then[INDENT]echo "Ja, $1 ist nicht identisch mit $vergl."[/INDENT]else[INDENT]echo "$1 ist identisch mit $vergl."[/INDENT]fi
echo ""</b>
Nur wenn diese beiden Strings identisch sind, wird der else-Zweig verarbeitet.
Ein weiteres Anwendungsbeispiel.
Code:
vi 05_wurde_argument_uebergeben
Code:
clear
# prüfen, ob ein Argument übergeben wurde
if [ $# == 0 ]
then[INDENT]echo "Es wurde kein Name angegeben."
echo "Der Name muss beim Scriptaufruf als Argument mit übergeben werden."[/INDENT]else[INDENT]echo "Mein Name ist $1"[/INDENT]fi
echo ""
Ist der Wert nicht 0, wird der else-Zweig ausgeführt und in unserem Beispiel der Satz "Mein Name ist xyz" ausgegeben.
Eine Anmerkung noch!
Nur weil wir hier nur echo-Befehle in den Abfragen benutzt haben, bedeutet das nicht, dass nichts Anderes möglich sei. Die Möglichkeiten sind da nahezu unbegrenzt, wie wir im Weiteren auch noch sehen werden.
-- test testen --
;-) Was wollen wir machen?
- dieses Kapitel widmet sich dem test.
Unix bietet uns ein Werkzeug mit dem Namen 'test'. Dies ist auch der Grund, warum ich davon abrate, einer Datei den Dateinamen 'test' zu geben!
Mit test lassen sich die verschiedensten Dinge abprüfen. Einige von den vielen vielen Möglichkeiten schauen wir uns mal genauer an.
Wir haben es eben sogar schon benutzt! An Stelle von
Code:
if [ $1 != $vergl ]
Code:
if test $1 != $vergl
Um uns mal einen Überblick zu verschaffen, welche Möglichkeiten uns das Werkzeug so gibt, geben wir in der Konsole mal
Code:
man test
Wie wir sehen, bietet test uns jede Menge Möglichkeiten.
Also, los geht's...
Code:
vi 06_test_anwenden01
Code:
clear
echo -n "Bitte geben Sie Ihre Lieblings-Obstsorte ein: "
read obst
if test -z $obst
then[INDENT]echo "Sie haben keine Obstsorte angegeben."[/INDENT]else[INDENT]echo "So so, Sie mögen also gerne $obst."[/INDENT]fi
echo ""
Ist dies der Fall, wird true, ansonsten false zurückgegeben.
Probieren wir beides aus. Wir starten das Script
Code:
sh 06_test_anwenden01
Geben wir hingegen beispielsweise 'Apfel' ein, ist der Rückgabewert von test false, da die Zeichenlänge ja nicht 0 ist, und somit wird der else-Zweig bearbeitet.
In der Manual zu test haben wir ja auch gelesen, dass sich dieses Werkzeug wunderbar dazu eignet um Dinge rund um Dateien abzufragen.
Wir werden uns an dieser Stelle noch nicht darum kümmern, sondern kommen an gegebender Stelle darauf zurück.
-- Schleifen --
;-) Was wollen wir machen?
- wir sind wieder bei Kontrollstrukturen und nehmen uns jetzt die erste (und später noch eine zweite) Schleife vor
Neuer Abschnitt, also erst mal eine neue Datei:
Code:
vi 07_meine_erste_schleife
In x wird der aktuelle Durchlauf gespeichert werden, was bedeutet:
Solange x <= 10, addiere 1 zu x.
Code:
clear
x=1
while [ $x -le 10 ]
do[INDENT]echo "x = $x"
x=`expr $x + 1`[/INDENT]done
echo ""
Wir erinnern uns, dass bei einer Wertzuweisung das $-Zeichen weggelassen werden muss.
Jetzt geht es in die Schleife. Eröffnet wird sie mit "while" und den eckigen Klammern. Auch hier ist es wieder wichtig, dass vor und nach den Klammern Leerzeichen sind.
Code:
$x -le 10
Nach der Bedingung folgt das Schlüsselwort "do", welches den auszuführenden Teil einleitet.
Der Part, der während des Schleifendurchlaufs ausgeführt werden soll, sollte wieder unbedingt eingerückt werden (auch hier empfehle ich zwei Leerzeichen).
Was tut unsere Schleife denn da überhaupt?
Code:
do[INDENT]echo "x = $x"
x=`expr $x + 1`[/INDENT]
Danach wird x mit dem Werkzeug 'expr' das wir ja schon kennen, um einen erhöht. Das ist ganz wichtig, da die Schleife sonst NIE enden würde, nur der Rechner irgendwann alle Viere von sich streckt und neugestartet werden müsste.
Wenn wir allerdings doch mal in so einer Endlosschleife hängen, können wir diese, und auch jeden anderen Programm-Ablauf, mit der Tastenkombination STRG+C (oder CTRL+C) abwürgen.
Der Dateiname unseres Scriptes hat es uns eigentlich schon verraten,... wir werden noch eine weitere Schleife basteln. Da es sich um eine Schleife handelt, die sich von while-Schleife unterscheidet, werden wir ihr eine neue Datei gönnen.
Code:
vi 07_for_schleife
Man könnte sagen, die for-Schleife kommt zum Einsatz, wenn die Anzahl der Durchläufe bekannt ist.
Wir dürfen nicht verzweifeln, wenn wir bei unseren ersten Versuchen die falsche Schleife anwenden, zum Ziel kommt man oft trotzdem.
Jetzt aber los! Wir wollen ein Script, dem beim Aufruf mehrere Variablen übergeben werden können.
Eben haben wir gesagt, dass sich eine for-Schleife eignet, wenn wir wissen, wie viele Durchläufe wir haben werden.
Wir erinnern uns, dass wir mit $# abprüfen können, wie viele Argumente beim Scriptaufruf übergeben wurden, also wissen wir, wie oft die Schleife durchlaufen werden muss, um alle Argumente wieder auf dem Bildschirm auszugeben.
Code:
clear
echo Uebergabeparameter: $*
for i in $*
do[INDENT]echo Hier steht: $i[/INDENT]done
echo ""
Code:
sh 07_for_schleife 2 4 6 8 10
Code:
Uebergabeparameter: 2 4 6 8 10
Hier steht: 2
Hier steht: 4
Hier steht: 6
Hier steht: 8
Hier steht: 10
An Stelle der Ausgabe, kann natürlich auch jede andere Aktion mit dem Argument gemacht werden!
-- Erstes kleines Programm --
;-) Was wollen wir machen?
- jetzt wollen wir unser neues Wissen mal anwenden, aber auch hier, werden wir immer wieder über Neues stolpern. Aber das kriegen wir schon hin!
Doch erst mal ein paar Vorbereitungen.
Legen wir erst mal eine Namensliste an. Womit? Na klar, mit dem vi!!
Code:
vi nameliste.txt
Code:
Heinz Oldmann
Semi Kolon
Ellen Bogen
Willi Walter
Nachdem wir die obrige Namensliste erstellt und den vi wieder verlassen haben, versuchen wir uns einmal an folgendem Befehl:
Code:
grep Ellen namenliste.txt
Code:
Ellen Bogen
Nun aber zu unserem Programm. Fangen wir ganz einfach und unkompliziert an.
Code:
vi 08_erstes_kleines_programm
Code:
clear
echo -n "Bitte geben Sie den zu suchenden String ein: "
read suche
echo ""
echo "Suchergebnis:"
echo ""
echo ""
echo "`grep $suche $1`"
echo ""
Code:
sh 08_erstes_kleines_programm namenliste.txt
Gäbe es noch einen weiteren Namen, der 'Ellen' enthält, würden beide Suchergebnisse untereinander ausgegeben.
Folgendes steht auf dem Programmplan:
- die Anzahl der Suchergebnisse sollen angezeigt werden
"Suchergebnis:" ersetzen mit "x Einträge gefunden", wobei x für die Anzahl der gefundenen Einträge steht - logisch! - es soll überprüft werden, ob überhaupt eine Datei als Argument übergeben wurde
- wenn ja, ob es sich wirklich um eine lesbare Datei handelt
- die Möglichkeit schaffen, zwei, oder mehr, Namenslisten anzugeben
Code:
clear
echo -n "Bitte geben Sie den zu suchenden String ein: "
read suche
echo ""
[B]echo "`grep -c $suche $1` Eintraege gefunden:"[/B]
echo ""
echo ""
echo "`grep $suche $1`"
echo ""
Prüfen wir nun ab, ob überhaupt ein Argument mit übergeben wurde.
Eine Variable hat uns ihre Hilfe angeboten und die nehmen wir gerne an.
In dieser Variable, mit dem Namen 'doit', werden wir eine 0 schreiben, wenn kein, und eine 1, wenn doch ein Argument übergeben wurde.
Und zwar prüfen wir das noch bevor wir unseren Suchstring eingeben, da das ja unnötig wäre, wenn eh keine Datei zum drin suchen angegeben wurde.
Code:
clear
if [ $# == 0 ]
then[INDENT]doit=0
echo "Es wurde keine Namensliste angegeben!"
[/INDENT]else[INDENT]doit=1[/INDENT]fi
if [ $doit == 1 ]
then[INDENT]echo -n "Bitte geben Sie den zu suchenden String ein: "
read suche
echo ""
echo "`grep -c $suche $1` Eintraege gefunden:"
echo ""
echo ""
echo "`grep $suche $1`"[/INDENT]fi
echo ""
Was aber, wenn man statt "namenliste.txt" einfach eine Zahl, oder anderen Unsinn, angibt?
Dumm gelaufen! Und darum werden wir die Abfrage erweitern, dass zusätzlich gefragt wird, ob das Argument eine lesbare Datei ist. Das Werkzeug test wird uns behilflich sein und aus der Manual wissen wir, dass '-r' genau das bei einer Datei abprüft, was wir wissen wollen.
Wenn also überhaupt ein Argument übergeben wurde, dann prüfen wir, ob es sich um eine existierende und lesbare Datei handelt und nur dann geht es weiter im Programm:
Code:
clear
if [ $# == 0 ]
then[INDENT]doit=0
echo "Es wurde keine Namensliste angegeben!"
[/INDENT]else[INDENT]# eine if-Abfrage im else-Zweig einer anderen Abfrage
if test -r $1 # wenn Datei existiert und lesbar ist
then[INDENT]doit=1[/INDENT]else[INDENT]doit=0
echo "Datei \"$1\" existiert nicht, oder ist nicht lesbar."[/INDENT]fi
[/INDENT]fi
if [ $doit == 1 ]
then[INDENT]echo -n "Bitte geben Sie den zu suchenden String ein: "
read suche
echo ""
echo "`grep -c $suche $1` Eintraege gefunden:"
echo ""
echo ""
echo "`grep $suche $1`"[/INDENT]fi
echo ""
Jetzt sehen wir auch, warum es sich gelohnt hat, die Abfrage nicht direkt in die unterste if-Abfrage einzubauen, sondern sie gesondert zu behandeln. Es würde gehen, aber so ist es übersichtlicher und kompfortabler und vor allem leichter erweiterbar, wie im nächsten Kapitel!
Bevor wir unser Script noch erweitern, muss es erst noch getestet werden.
Um es auch an einer nicht lesbaren Datei zu testen, werden wir diese jetzt anlegen und das Leserecht nehmen.
Code:
touch nicht_lesbar
Code:
chmod 333 nicht_lesbar
Code:
Datei "nicht_lesbar" existiert nicht, oder ist nicht lesbar.
;-) Was wollen wir machen?
- unser kleines Progrämmchen bekommt jetzt seinen Feinschliff. Mit dem erlernten Wissen um die Anwendung von Schleifen, werden wir uns eine davon schnappen um den Benutzer unseres Scriptes die Möglichkeit zu geben, mehr als ein Argument zu übergeben
- die Anzahl der Suchergebnisse sollen angezeigt werden
"Suchergebnis:" ersetzen mit "x Einträge gefunden", wobei x für die Anzahl der gefundenen Einträge steht - logisch! - es soll überprüft werden, ob überhaupt eine Datei als Argument übergeben wurde
- wenn ja, ob es sich wirklich um eine lesbare Datei handelt
Der Befehl dazu ist 'cp' gefolgt von der zu kopierenden Datei und dem Zielnamen:
(ich erinnere noch mal an die Möglichkeit der Autovervollständigung der Datei-Namen durch die TAB-Taste!!)
Code:
cp 08_erstes_kleines_programm 08_erstes_kleines_programm_teil2
Code:
vi 08_erstes_kleines_programm_teil2
Code:
clear
if [ $# != 0 ] # wenn ueberhaupt ein Argument uebergeben wurde
then[INDENT]echo -n "Bitte geben Sie den zu suchenden String ein: "
read suche
for i in $* # alle Argumente der Reihe nach ansprechen
do[INDENT]if test -r $i # existiert Datei und ist lesbar?
then[INDENT]echo ""
echo "`grep -c $suche $i` Eintraege in \"$i\"."
echo ""
echo "`grep $suche $i`"
[/INDENT]fi
[/INDENT]done[/INDENT]else[INDENT]echo "Es wurde keine Datei zum Suchen mit uebergeben!"[/INDENT]fi
echo ""
In der ersten If-Abfrage prüfen wir, ob denn überhaupt ein Argument, also eine Datei, übergeben wurde. Ist dies nicht der Fall, kommt eine entsprechende Meldung und unser Script ist schon am Ende.
Wurde aber doch mindestens eine Datei angegeben, so wird im nächsten Schritt nach dem zu suchenden String gefragt. Wir geben diesen ein und es geht in die For-Schleife (auch Zählschleife genannt). Diese arbeitet nun alle übergebenen Dateien ab. Wenn nur eine Datei übergeben wurde, wird auch nur eine abgearbeitet. Bei zwei, hat die Schleife zwei Durchläufe.
Das wollen wir doch mal testen.
Wir haben ja bereits die Datei "namenliste.txt". Kopieren wir diese doch einfach...
Code:
cp namenliste.txt namenliste2.txt
Wie rufen wir unser Script denn jetzt mit zwei Argumenten auf? Nichts leichter als das:
Code:
sh 08_erstes_kleines_programm_teil2 namenliste.txt namenliste2.txt
Fertig!
-- 6 aus 49 --
;-) Was wollen wir machen?
- Lottozahlen generieren!
Und warum? Na ja. Zum Einen, weil das in fast jedes Beginner-Tut gehört und weil ich danach gefragt wurde.
Kein Müdigkeit vortäuschen...
Code:
touch 09_lotto
vi 09_lotto
Weil es mit der Zeit jetzt ein wenig unübersichtlich wird, werde ich ab jetzt, wo es sich anbietet, statt des Kommentars eine Zahl anfügen und unter dem Quellcode erläutern, was an Stelle des Kommentars dort steht.
Code:
clear
echo `touch lotto_temp` # 1
i=0
while [ $i -lt 6 ] # 2
do[INDENT]rnd=$((RANDOM % 49 + 1)) # 3
echo $rnd >> lotto_temp # 4
i=`expr $i + 1`[/INDENT]done
echo `sort -n lotto_temp` # 5
echo `rm lotto_temp` # 6
- temporäre Datei zum Zwischenspeichern der Zahlen anlegen
- solange i kleiner 6 ist
- Zufallszahl ermitteln und in Variable 'rnd' schreiben
(durch das '% 49 + 1' stellen wir sicher, dass nur Zahlen im gewünschten Bereich gewählt werden - das '%' steht in diesem Fall für Modulo) - die Zufallszahl in die temporäre Datei schreiben
(das '>>' bedeutet, dass die Datei angehängt wird. Ein '>' würde bewirken, dass evtl. schon drin stehende Zahlen einfach überschrieben würden) - Diese Zeile könnten wir auch auslassen. Allerdings würde unsere Ausgabe dann nicht sortiert ausgegeben, sondern quer durcheinander.
Bei dem 'sort'-Befehl bewirkt das -n, dass nummerisch Sortiert wird, was für unser Beispiel genau das richtige ist, da es sich ja um Zahlen handelt.
Der 'sort'-Befehl ist hier auch dafür zuständig, dass die Ziffern auf dem Bildschirm ausgegeben werden. - rm --> remove
Wir löschen die anfangs angelegte Datei, denn sie ist schließlich temporär und wird nicht weiter benötigt.
Das gehört geändert.
Und genau darum kümmern wir uns jetzt.
Da wir geschachtelte Schleifen mögen, werden wir jetzt einfach eine weitere Schleife einbauen, die solange eine neue Zufallszahl anfordert, bis eine gefunden wurde, die noch nicht in der 'lotto_temp' steht.
Neue / geänderte Zeilen sind wieder fett abgebildet.
Code:
clear
echo `touch lotto_temp`
[B]rnd=$((RANDOM % 49 + 1))[/B]
i=0
while [ $i -lt 6 ]
do[INDENT][B]while [ `grep -c $rnd lotto_temp` -gt 0 ]
do[INDENT]rnd=$((RANDOM % 49 + 1))[/INDENT]done
[/B]echo $rnd >> lotto_temp
i=`expr $i + 1`
[/INDENT]done
echo `sort -n lotto_temp`
echo `rm lotto_temp`
Das '-gt' steht für 'greater than / größer als' (nicht größer/gleich als!!)
So wird so lange eine neue Zufallszahl angefordert, bis die Anzahl = 0 ist und wir haben fortan keine Duplikate mehr.
Viel Glück bei der nächsten Ziehung!
-- Lock-Screen --
;-) Was wollen wir machen?
- Unsere Konsole, und damit unser System, vor dem Zugriff Unbefugter schützen.
Jetzt nicht gleich das Browser-Fenster schließen! Klingt komplizierter als es ist.
Code:
touch 10_lockscreen
vi 10_lockscreen
Nun wäre es strategisch unpraktisch, wenn das PW beim Festlegen lesbar auf dem erscheinen würde.
Deshalb schauen wir mal, wie wir das umgehen können. Das Werkzeig 'stty' hilft uns.
Es ermöglicht es die Eingabe unsichtbar geschehen zu lassen.
Code:
stty -echo
Code:
echo -n "PW eingeben: "
stty -echo
read CODE
stty echo
echo ""
echo "Ihr PW: $CODE"
Wir stellen fest, dass sich der Cursor sich nicht von der Stelle bewegt. So kann niemand, der einem über die Schulter guckt, die Zeichenanzahl unseres PWs erkennen.
Nachdem wir unsere Eingabe, wie gewohnt, mit ENTER bestätigen, wird unser PW ausgegeben.
Sicher, das ist sinnfrei! Aber es handelt sich hier ja nur um ein Beispiel.
Löschen wir die unteren beiden Zeilen (im vi in die entsprechende Zeile gehen und zwei mal die 'd'-Taste drücken).
Code:
echo -n "PW eingeben: "
stty -echo
read CODE
stty echo
clear
MATCH=""
DELAY=1
In der Variable 'MATCH' erfassen wir später die PW-Eingaben.
Wir werden unserem Script einen kleinen Leckerbissen verpassen. Nach jeder falschen Eingabe, wird die Wartezeit auf die nächste Eingabe verdoppelt.
Den Startwert von 1 weisen wir der Variable 'DELAY' zu.
Jetzt kümmern wir uns um die Schleifenbedingung:
Code:
while [ "$MATCH" != "$CODE" ]
do
Was packen wir jetzt in den Schleifenkörper?
- die Warteanweisung
- die Verdopplung der Wartezeit
- die Eingabe des Passworts
Code:
while [ "$MATCH" != "$CODE" ]
do[INDENT]sleep $DELAY
echo -n "Bitte Passwort eingeben: "
read MATCH
DELAY=`expr $DELAY \* 2`[/INDENT]done
Code:
echo -n "Bitte Passwort festlegen: "
stty -echo
read CODE
stty echo
clear
MATCH=""
DELAY=1
while [ "$MATCH" != "$CODE" ]
do[INDENT]sleep $DELAY
echo -n "Bitte Passwort eingeben: "
read MATCH
DELAY=`expr $DELAY \* 2`[/INDENT]done
echo
Dafür zuständig ist die Zeile
Code:
DELAY=`expr $DELAY \* 2`
Na gut, noch mal ganz kurz: Der Benutzer wird aufgefordert ein Passwort einzugeben und seine Eingabe wird der Variable 'MATCH' zugewiesen.
Rufen wir das Script mal auf:
Code:
sh 10_lockscreen
Geben wir das richtige ein, können wir weiterarbeiten.
Wir haben bei unseren Schleifen-Scripten die Möglichkeit kennen gelernt, mit der Tastenkombination "STRG + C" einen Ablauf abzubrechen.
Oh, was ist das? Das geht hier ja auch - sehr ungünstig!
Also müssen wir noch mal ran.
Eine andere,... nennen wir es erst mal Oberfläche, erlaubt es uns die Tastenkombination zu unterbinden.
Den Aufruf dieser anderen Bash erreichen wir wie folgt mit dem Werkzeug 'trap'
Die in unser vorhandenes Script einzufügende Zeile ist fett gedruckt
Code:
echo -n "Bitte Passwort festlegen: "
stty -echo
read CODE
stty echo
clear
[B]trap "" 2 3[/B]
MATCH=""
DELAY=1
while [ "$MATCH" != "$CODE" ]
do[INDENT]sleep $DELAY
echo -n "Bitte Passwort eingeben: "
read MATCH
DELAY=`expr $DELAY \* 2`[/INDENT]done
echo
-- Idealgewicht --
;-) Was wollen wir machen?
- Unser Idealgewicht (berechnen) - ein bisschen Wiederholung
Code:
touch 11_idealgewicht
vi 11_idealgewicht
- Mann
kg = (Körpergröße in cm - 100) * 0,9 - Frau
kg = (Körpergröße in cm - 100) * 0,85
Vom Benutzer benötigen wir die Eingabe von Körpergröße (in cm) und das Körpergewicht (in kg)
Code:
clear
echo -n "Bitte geben Sie Ihre Körpergröße in cm ein: "
read groesse
echo -n "Bitte geben Sie Ihr Gewicht ein: "
read gewicht
Als erstes ziehen wir die 100 von der Körpergröße ab und speichern das Ergebnis schon mal in der Variable für das Idealgewicht.
Zur Berechnung benutzen wir wieder unser Werkzeug 'expr' - klar, oder?
Code:
ideal=`expr $groesse - 100`
Ach, ist gar kein Problem. Als mathematisch versierte Scripter erkennen wir sofort folgenden Lösungsweg:
Wir multiplizieren mit 9 und dividieren anschließend durch 10.
Code:
ideal=`expr $ideal \* 9`
ideal=`expr $ideal \/ 10`
Code:
echo ""
echo "Ihr Idealgewicht wäre $ideal kg."
Dazu berechnen wir im ersten Schritt die Differenz
Code:
differenz=`expr $gewicht - $ideal`
Code:
if [ $differenz -gt 0 ]
then[INDENT]echo "Sie haben Übergewicht: $differenz kg."[/INDENT]else
fi
Es wird geprüft, ob die Differenz echt größer als 0 ist.
Ist dies nicht der Fall, geht es in den Else-Zweig, den wir jetzt füllen
Code:
else
if [ $differenz -lt 0 ][INDENT]then[INDENT]differenz=`expr $differenz \* -1`
echo "Sie haben Untergewicht: $differenz kg."
[/INDENT]else[INDENT]echo "Sie haben Idealgewicht!"[/INDENT]fi[/INDENT]fi
Trifft das nicht zu, kann nur noch ein Fall eintreten, der Else-Zweig wird aufgerufen.
Rufen wir das Script mal auf:
Code:
sh 11_idealgewicht
Das war es für's erste...
Über Verbesserungsvorschläge oder Bemerkungen anderer Art würde ich mich freuen (besonders wenn es jemandem gefallen hat )
MfG Kryp