[Bash-Programmierung] Umleitungen, grep und Co.

    • Offizieller Beitrag

    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:

      Code
      example.comgoogle.dealisdf.ruwikipedia.de


      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:

      Code
      ping $DOMAIN -c1 2> /dev/null


      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:

      Code
      > ergebnis.txt


      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:

      Code
      ([0-9\.?]+)



      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:

      Code
      echo "<version>3.0.15.1</version>" | egrep -o '([0-9\.?]+)'


      Das sollte dann folgendes Ergebnis auf der Kommandozeile liefern:

      Zitat

      $ echo "<version>3.0.15.1</version>" | egrep -o '([0-9\.?]+)'
      3.0.15.1


      Wer 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.123


      Das 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:

      Code
      cat seite.html | tr "\n" "|"


    So... Viel Text und Code. Ich hoffe, ich konnte einigen weiterhelfen und sie mit weiterem Wissen füllen. :D


    Viel Spaß damit und schreibt in die Kommentare, wenn ihr davon mehr wollt oder besondere Wissenswünsche habt! ;)

  • Hallo,


    habe die 2 Tutorials jetzt mal durchgelesen.
    Mich würde folgednes noch interessieren:


    - Verbindung zu einer Datenbank(MySQL, POSTGRES)
    - Das Insert, Update, löschen und zählen der Datensätze mit den jeweiligen Datenbanken
    - Die Verbindung zu einer Adresse mit Port. Speziell z.B bei Teamspeak wie man dort ein "listen" aufbauen kann(also ein warten auf ein event). Also: Wenn ein Client z.B. connected mache dies, wenn er einen Channel switcht, mache das, usw.
    - Kann man die Bash Programmierung mit z.B PHP verbinden? Also ein Request an PHP senden, welcher dort dann verarbeitet wird?


    Sonst gute Tutorials, gefallen mir sehr :)
    Gute Arbeit!


    Grüße

    • Offizieller Beitrag

    Hallo Pagian,


    - Verbindung zu einer Datenbank(MySQL, POSTGRES)
    - Das Insert, Update, löschen und zählen der Datensätze mit den jeweiligen Datenbanken


    Ja, das ist möglich und geht zum Beispiel anhand einer MySQL Datenbank so:


    - Die Verbindung zu einer Adresse mit Port. Speziell z.B bei Teamspeak wie man dort ein "listen" aufbauen kann(also ein warten auf ein event). Also: Wenn ein Client z.B. connected mache dies, wenn er einen Channel switcht, mache das, usw.


    Ja, das geht bestimmt auch, aber hierfür gibt es meines Wissens nach ein extra dafür angefertiges Tool, welches eine deutlich bessere Performance leistet. Mir fällt der Name der Software nur gerade leider nicht ein. @Thomas könnte es vielleicht wissen.


    - Kann man die Bash Programmierung mit z.B PHP verbinden? Also ein Request an PHP senden, welcher dort dann verarbeitet wird?


    Du kannst in PHP-Skripten Shell-Skripte aufrufen, indem du die PHP-Funktion shell_exec nutzt: PHP: shell_exec - Manual


    Meines Wissens nach, kannst du aber auch anders rum damit arbeiten: Das Shell Skript führt das PHP-Skript aus. Hierfür musst du halt einfach mit "php skript.php" das PHP-Skript ausführen und die Werte, die das PHP-Skript liefert, weiter verarbeiten.


    Sonst gute Tutorials, gefallen mir sehr :)
    Gute Arbeit!


    Vielen Dank! :)

  • Ja, das ist möglich und geht zum Beispiel anhand einer MySQL Datenbank so:


    Okay, sieht gut aus. Wie sieht es mit SQL Injections hier aus?


    Ja, das geht bestimmt auch, aber hierfür gibt es meines Wissens nach ein extra dafür angefertiges Tool, welches eine deutlich bessere Performance leistet. Mir fällt der Name der Software nur gerade leider nicht ein. Thomas könnte es vielleicht wissen.


    Okay, also ich möchte nichts direkt nur für Teamspeak sonder Allgemein(Teamspeak war nur ein Beispiel). Weitere Beispiele wären Mumble, Vintrelo(oder so) oder auch simple System die so etwas erfordern.


    Du kannst in PHP-Skripten Shell-Skripte aufrufen, indem du die PHP-Funktion shell_exec nutzt: PHP: shell_exec - Manual


    Meines Wissens nach, kannst du aber auch anders rum damit arbeiten: Das Shell Skript führt das PHP-Skript aus. Hierfür musst du halt einfach mit "php skript.php" das PHP-Skript ausführen und die Werte, die das PHP-Skript liefert, weiter verarbeiten.


    Das mit PHP wusste ich, mir ging es darum das erst das Shell Script aufmerksam wird und dieses dan an ein PHP Script sendet, welches dann diese Daten weiter verarbeitet.

    • Offizieller Beitrag

    Bezüglich SQL Injections: Das hängt vom Programmierstil ab. Wer schlampig programmiert, hat immer Probleme, daher investiert man als Programmierer auch mehrere Stunden, anstatts Minuten in ein auch noch so kleines Projekt. ;)


    Ja, das von mir gemeinte Tool ist für alles gedacht - nicht nur für TS. Das ist ein Event-Trigger und führt dann entsprechende Aktionen aus. Thomas hat mir das mal gezeigt, wenn ich mich nicht irre.


    Ja, du kannst vom Shell-Skript aus auch an das PHP-Skript Daten senden. Hatte ich ja erwähnt.

  • Dieses Thema enthält 3 weitere Beiträge, die nur für registrierte Benutzer sichtbar sind, bitte registrieren Sie sich oder melden Sie sich an um diese lesen zu können.