Hallo,
aufgrund der hohen Nachfrage gibt es nun den zweiten Teil zum Thema Bash-Programmierung. Hierfür wird der erste Teil voraus gesetzt: Einführung in die Bash-Programmierung
Inhaltsverzeichnis
- Umleitungen
- grep
- cut
- tr
Das wohl meist gebrauchte bei der Bash-Programmierung ist die Umleitung von irgendwelchen Streams/Aus- bzw. Eingaben, daher fangen wir auch damit an:
-
Umleitungen
Was sind Umleitungen überhaupt? Man kann mit Hilfe von sogenannten Streamoperatoren bestimmte Ein- bzw. Ausgaben umleiten. Solche Streamoperatoren sind zum Beispiel folgende: <, >, 2>, 2>&1, |Letzteres würde ich mal außen vorlassen, denn das leitet nicht wirklich was um, sondern gibt es an den danach stehenden Befehl weiter.
Nun gut. Unser Skript sieht wie folgt aus:
Bash#!/bin/bash# Überprüfe, ob alle Domains erreichbar sindwhile read DOMAIN; do if [[ $(ping $DOMAIN -c1 2> /dev/null) ]]; then # Domain ist erreichbar :) echo "$DOMAIN ist erreichbar!"; else # Domain ist nicht erreichbar :( echo "$DOMAIN ist NICHT erreichbar!"; fidone < domains.txt
Und unsere "domains.txt" Datei hat folgenden Inhalt:So ermöglicht uns das Skript folgendes: Wir können pro Zeile eine zu überprüfende Domain in die Datei "domains.txt" reinschreiben und das Skript überprüft dann zeilenweise, ob die jeweilige Domain erreichbar ist oder nicht - anhand eines Pings.
Mit der letzten Zeile des Skripts "done < domains.txt" sagen wir der WHILE-Schleife, dass sie als Eingabe/Input unsere Datei einlesen und jede Zeile einzeln in die Variable "DOMAIN" speichern soll. Danach erfolgt dann der normale Vorgang der IF-Abfrage für jede einzelne Zeile/Domain der domains.txt.
Wie ihr gesehen habt, ist der Ping Befehl auch mit einer Umleitung aufgebaut:
Das "2>" sorgt dafür, dass alle sogenannten "stderr", also "Fehlerausgaben" nach "/dev/null" ausgegeben bzw. umgeleitet werden. Das hat den Sinn, dass wir bei unserer Wunschausgabe keine Fehlerausgaben sehen möchten, sonst sähe das nämlich so aus:Zitat$ ./skript.sh
example.com ist erreichbar!
google.de ist erreichbar!
ping: unknown host alisdf.ru
alisdf.ru ist NICHT erreichbar!
wikipedia.de ist erreichbar!
Es soll aber so aussehen:Zitat$ ./skript.sh
example.com ist erreichbar!
google.de ist erreichbar!
alisdf.ru ist NICHT erreichbar!
wikipedia.de ist erreichbar!Gut. So liest man also Dateien ein und leitet Fehlerausgaben ins Nichts um. Wir könnten nach "domains.txt" aber auch noch folgenden Code anhängen:
Dann würde die Ausgabe des Skripts nicht angezeigt werden, sondern in die Datei "ergebnis.txt" reingeschrieben werden, welche wir uns danach einfach ausgeben lassen können:Zitat$ ./skript.sh
$ cat ergebnis.txt
example.com ist erreichbar!
google.de ist erreichbar!
alisdf.ru ist NICHT erreichbar!
wikipedia.de ist erreichbar!
Sowas wird häufig dann benötigt, wenn man zum Beispiel größere Datensätze mehrfach weiterverarbeiten muss und das aber nicht mit Variablen geht. Da man nicht nur umleiten, sondern auch "filtern" möchte, gehen wir zum nächsten Punkt über: grep -
grep
"grep" ist ein Programm zur Suche und Filterung definierter Zeichenketten aus Dateien, sowie Variablen. Wenn man zum Beispiel einen String, also eine Zeichenkette mit unnötigen Zeichen hat, kann man sich mit Hilfe von grep den benötigten Teil anhand von Regular Expressions (= Regex) ganz einfach herausfiltern.Beispiel: Wir haben das:
Zitat<version>3.0.15.1</version>
Hiervon wollen wir nur "3.0.15.1", daher bauen wir uns erstmal unsere Regex. Um diese schnellst möglich zu bauen und erfolgreich zu sein, kann ich die Webseite Rubular.com empfehlen. Hier gibt man seinen Code, den man filtern möchte ein und oben in der Zeile die zu bauende Regex:
Eine ganz einfache Regex wäre der eindeutige String, den wir suchen. (Siehe Screenshot.)Problem an der "Regex" ist jedoch, dass das die Version "3.0.15.2" und alle anderen Versionen nicht mehr finden würde. Aus diesem Grund brauchen wir etwas allgemeines, was immer zutrifft. Hier muss man sich auch Gedanken über das Ergebnis bzw. Ziel - je nachdem wie man es sieht - machen. Ist die Version immer gleich aufgebaut oder hat sie auch mal nur drei Ziffern? Sie kann ja zum Beispiel auch so aussehen: 3.0.16, 3.0.16.1, 3.0.16.123,...
Daher empfehle ich eine möglichst allgemeine Regex, wie zum Beispiel diese:
Gesplittet bedeutet die Regex folgendes: Alle Zahlen von 0-9 (= dafür die eckigen Klammern und der Bindestrich um die Zahlen) mindestens 1x (= dafür das "+") und vom Punkt kann, muss aber keiner da sein (= daher das "?"). Der Backslash (= "\") ist lediglich zum escapen, da ein normaler "Punkt" oder Backslash sonst "jedes beliebiges Zeichen" bedeutet. Die runden Klammern um alles bedeuten nur, dass ich lediglich das Ergebnis dann sehen und haben möchte. Er speichert es mir dann in ein sogenanntes Array.Gut. Jetzt können wir uns unseren Befehl zum Filtern bauen:
Das sollte dann folgendes Ergebnis auf der Kommandozeile liefern:Zitat$ echo "<version>3.0.15.1</version>" | egrep -o '([0-9\.?]+)'
3.0.15.1Wer es mit anderen Versionen testet, wird auch feststellen, dass es immer funktionieren wird:
Zitat$ echo "<version>3.0.16</version>" | egrep -o '([0-9\.?]+)'
3.0.16$ echo "<version>3.0.16.123</version>" | egrep -o '([0-9\.?]+)'
3.0.16.123$ echo "<version>71.6.16.123</version>" | egrep -o '([0-9\.?]+)'
71.6.16.123Das könnten wir jetzt auch genau so im Skript einbauen.
-
cut
"cut" ist ein Programm zur Extraktion von Strings. Hiermit kann man zum Beispiel anhand eines Trennzeichens Strings aufteilen und entsprechend neu sortieren oder nur notwendiges ausgeben lassen.Beispiel:
Aus...Zitat$ echo "Das ist der Schuh vom Mann. Gruss, Manitu."
Das ist der Schuh vom Mann. Gruss, Manitu.
...wird das...Zitat$ echo "Das ist der Schuh vom Mann. Gruss, Manitu." | cut -d " " -f 1-2,8
Das ist Manitu.Hier gebe ich den Text "Das ist der Schuh vom Mann. Gruss, Manitu." an den nächsten Befehl "cut" weiter, welcher ihn weiter verarbeitet. Der Parameter "-d" gibt an, dass das nachfolgende Trennzeichen in den Anführungszeichen verwendet werden soll, um den Text in einzelne Bereiche/Teile zu schneiden. In dem Fall ist es ein einfaches Leerzeichen. Man kann auch Kommas, Semikolons, Zeilenumbrüche und Co. verwenden. Mit dem Parameter "-f" sagt man dann nur noch, welche geschnittenen Teile des Textes man jetzt haben möchte. Ich sage hier "1 bis 2" UND 8.
Da der Trenner das Leerzeichen ist, wird jedes Wort ein Teil. Wörter mit einem Zeichen hinten oder vorne dran, werden das Zeichen ebenfalls mit drin haben, da das dann zum Teil dazu gehört. Bei dem Trenner "." würde ich zum Beispiel folgendes Ergebnis erhalten:
Zitat$ echo "Das ist der Schuh vom Mann. Gruss, Manituh." | cut -d "." -f 1
Das ist der Schuh vom Mann$ echo "Das ist der Schuh vom Mann. Gruss, Manituh." | cut -d "." -f 2
Gruss, Manituh
Ja, da ist am Anfang ein Leerzeichen vor "Gruss", denn nach dem Punkt war für den ersten Teil Schluss und daher gehört zum zweiten Teil das führende Leerzeichen dazu. -
tr
Das Programm "tr" dient in Texten dazu, systematisch Zeichen durch andere zu ersetzen. Hierdurch kann man zum Beispiel alle Leerzeichen oder Zeilenumbrüche einfach rauslöschen:Zitat$ echo "Das ist der Schuh vom Mann. Gruss, Manituh." | tr -d " "
DasistderSchuhvomMann.Gruss,Manituh.Manchmal ist es zum Beispiel nötig, dass man einen Text in einer einzigen Zeile hat, um ihn besser bzw. überhaupt bearbeiten zu können. Ich habe das zum Beispiel für eine HTML-Seite benötigt, die ich ausgewertet habe. Hierfür war es nötig, dass alles in einer Zeile stand, daher habe ich einfach alle Zeilenumbrüche rausgelöscht bzw. durch ein Trennzeichen ersetzt, damit ich den Text weiterverarbeiten kann. In diesem Fall wurden die Zeilenumbrüche durch das Pipe-Zeichen ersetzt:
So... Viel Text und Code. Ich hoffe, ich konnte einigen weiterhelfen und sie mit weiterem Wissen füllen.
Viel Spaß damit und schreibt in die Kommentare, wenn ihr davon mehr wollt oder besondere Wissenswünsche habt!