Autor Thema: Scriptprogrammierung unter Linux  (Gelesen 14800 mal)

0 Mitglieder und 1 Gast betrachten dieses Thema.

Offline Dennis

  • HT4U.net Redakteur
  • 64-Bit-Prozessor
  • *****
  • Beitr├Ąge: 5939
  • Geschlecht: M├Ąnnlich
  • Killerspiele-Spieler!
    • Profil anzeigen
    • Meine :)
Scriptprogrammierung unter Linux
« am: 21. Mai 2005, 12:41:08 »
Und noch eine :D

Erstellen von Scripten unter Linux


Ein Script in Linux ist nicht anderes als eine Textdatei mit Befehlen, die von einer Linux-Shell interpretiert und ausgef├╝hrt werden. Zu den normalen Befehlen geh├Âren aber auch noch logische Konstrukte wie die if und case Anweisungen, sowie die kopfgesteuerte Schleife mit den Bedingungen while oder until. Die for Konstruktion gibt es hier auch, nimmt aber eine andere Funktion ein als man es sonst gew├Âhnt ist, dazu aber sp├Ąter mehr.

Der Anfang eines jeden Script, man braucht eine leere Textdatei diese kann mit touch erstellt und dann mit einem Editor bearbeitet werden. Der Befehl dazu w├Ąre touch Dateiname alternativ dazu kann man auch eine nicht existente Datei mit dem vi aufrufen, da dieser die Datei dann unter dem Namen wie aufgerufen speichert. Gebe ich also den Befehl vi testscript.sh ein, so erstellt mir der vi sofort eine leere Textdatei mit dem Namen testscript.sh.

Der erste Schritt w├Ąre geschafft man ist in einer leeren Datei. Um jetzt aber die Datei zu bearbeiten muss der vi erst vom Kommandomodus in den Eingabemodus gebracht werden, dazu dr├╝ckt man einfach die Taste i und schon wartet der Cursor auf die Eingabe. Bevor man aber anf├Ąngt fehlt noch das sogenannte Magic Cookie. Das Magic Cookie ist der Eintrag in der ersten Zeile und signalisiert in welcher Shell das Script ausgef├╝hrt werden soll. In unserem Fall lautet der Eintrag immer #!/bin/sh weil f├╝r unser script die normale Shell ausreicht und in dieser auch standardm├Ą├čig die Scripts ausgef├╝hrt werden.

Weitere Shells sind:
/bin/bash   Bourne again Shell das ist auch die Standard Login-Shell
/bin/ksh   Korn-Shell
/bin/csh   C-Shell

Beim benutzen einer anderen Shell ├Ąndert sich unter Umst├Ąnden auch die Syntax f├╝r einige Befehle. Es setzen zwar alle erweiterten Shells auf die urspr├╝ngliche Shell auf, bringen aber zus├Ątzliche Funktionen mit was an einigen Stellen zur Folge hat dass bestimmte Syntaktische Merkmale anders interpretiert werden.

Jetzt kann der erste Eintrag geschrieben werden. Ein ganz einfaches Script w├╝rde so aussehen.

#!/bin/sh
echo "Dieses Verzeichnis enth├Ąlt folgende Dateien und/oder Ordner"
ls -lF

Jetzt diese Datei speichern und ausf├╝hren. Dazu gibt es mehrere M├Âglichkeiten entweder man ├╝bergibt die Datei direkt an die shell mit dem Befehl sh testscript.sh oder man startet das script mit einem direkten Aufruf. In diesem Falle w├Ąre das /home/gilke/testscript.sh, f├╝r die 2. Variante muss der Shell aber noch erkl├Ąrt werden dass man die Datei ausf├╝hren kann. Anders als bei Windows definieren sich in Linux ausf├╝hrbare Dateien nicht durch ihre Endung sondern durch ein Attribut. Attribute ├Ąndert man mit dem Befehl chmod. Das Hinzuf├╝gen von Ausf├╝hrrechten f├╝r alle Nutzer ist der Befehl
chmod a+x /home/gilke/testscript.sh.     alle+execute Dateiname mit a-x w├╝rden die Attribute f├╝rs ausf├╝hren wieder gel├Âscht werden.

Jetzt kann das Script aber sp├Ątestens ausf├╝hrt werden.
Dieses Beispiel war aber etwas langweilig, da ein einzelner Befehl nicht wirklich Sinn und zweck eines Scripts ist. Wir wollen ein Script bauen dass uns mit Hilfe des Befehls ping angibt ob ein Rechner im Netzwerk online oder offline ist. Es soll aber nur die Meldung erscheinen "Der Rechner ist online" oder "Der Rechner ist offline". Die Angabe des Rechnername soll per Parameter erfolgen d.h. ich rufe dass Script wie folgt auf: /home/gilke/testscript.sh edv28.
 
In dem Script machen wir uns zu nutze wie Linux Befehlsausgaben handhabt, und zwar besteht ja die M├Âglichkeit dass der Befehl ping gelingt und eine Antwort vom Host kommt oder er gibt einen Fehler zur├╝ck. Und genau dieses kann man mit dem Konstrukt if abfragen.

Aufbau von if:

if ping -c1 edv28
then
  echo "Der Zielrechner ist online"
else
  echo "Der Zielrechner ist offline"
fi

Hier sieht man dass if den Befehl ping auswertet und je nachdem ob der Befehl gelingt oder auch nicht, kommt dann wahr oder falsch zur├╝ck und er f├╝hrt den then Zweig bei wahr oder den else Zweig bei falsch aus. Das -c1 hinter dem ping legt fest wie viele pakete gesendet werden in unserem Fall reicht -c1. In Windows ist der Standard 4 Pakete zu senden das w├Ąre dann in unserem Falle
ping -c4 edv28. F├╝hren wir also dieses script einmal aus

[gilke@sonny gilke]$ /home/gilke/testscript.sh
PING edv28.iplan.dklb.de (172.21.1.128) 56(84) bytes of data.
64 bytes from edv28.iplan.dklb.de (172.21.1.128): icmp_seq=0 ttl=128 time=0.320 ms

--- edv28.iplan.dklb.de ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.320/0.320/0.320/0.000 ms, pipe 2
Der Zielrechner ist online
[gilke@sonny gilke]$

Hier sehen wir das leider auch s├Ąmtliche Ausgaben die der Befehl macht mit ausgegeben werden wir wollten doch aber nur "Der Zielrechner ist online" sehen. Abhilfe schafft hier die M├Âglichkeit die Ausgabe nicht an den Bildschirm sondern in eine Datei zu leiten. Da wird die eigentliche Ausgabe aber nicht speichern wollen gibt es in Linux eine Datei die wie ein schwarzes Loch fungiert das ist die /dev/null. Alles was in diese Datei geschrieben wird verschwindet im Nirvana. Die Umleitung erfolgt ganz einfach mit einem >. ├ändern wir also das Script ab:

if ping -c1 edv28 > /dev/null
then
  echo "Der Zielrechner ist online"
else
  echo "Der Zielrechner ist offline"
fi

und f├╝hren es erneut aus. Und wie wir sehen es klappt.

[gilke@sonny gilke]$ /home/gilke/testscript.sh
Der Zielrechner ist online
[gilke@sonny gilke]$

Jetzt haben wir aber immer noch das Problem das wir den Rechnernamen in dem Script haben und nicht als Parameter ├╝bergeben haben. Dieses Problem ist aber in Linux sehr elegant zu l├Âsen. Rufen wir das script mit /home/gilke/testscript.sh edv28 auf so nimmt im script die spezielle Scriptvariable $1 den als Parameter ├╝bergebenen Wert an. ├ändern wir also das Script wie folgt ab, aber kurz noch ein paar weitere spezielle Scriptvariablen:

$#   Summe aller ├╝bergeben Argumente
$0   Name des laufenden Scriptes
$*   Alle ├╝bergebenen Argumente in einem String
$1   1. ├╝bergebens Argument, $2 w├Ąhre dann 2. usw.
if ping -c1 $1 > /dev/null
then
  echo "Der Zielrechner ist online"
else
  echo "Der Zielrechner ist offline"
fi

und das Ergebnis
[gilke@sonny gilke]$ /home/gilke/testscript.sh edv28
Der Zielrechner ist online
[gilke@sonny gilke]$

Jetzt testen wir was passiert wenn der Host offline ist.

[gilke@sonny gilke]$ /home/gilke/testscript.sh offlinehost
ping: unknown host offlinehost
Der Zielrechner ist offline
[gilke@sonny gilke]$

Hier sehen wir dass die Fehlermeldung wie bei der ersten Version die Standardausgabe noch mit ausgegeben werden. Dass > hinter dem Befehl bewirkt n├Ąmlich nur dass die Ausgabe umgeleitet wird, die ein erfolgreiches Ausf├╝hren des Befehls zur Folge hat. Gibt der Befehl allerdings eine Fehlermeldung zur├╝ck so gibt er diese immer noch am Bildschirm aus. Also muss es noch eine M├Âglichkeit geben die Fehlerausgabe auch auf /dev/null umzuleiten. Diese sieht wie folgt aus:

if ping -c1 $1 > /dev/null 2>&1

um es einfacher zu erkl├Ąren schreiben wir den Befehl wie folgt

if ping -c1 $1 1> /dev/null 2>&1

mit > oder 1> wird die Standardausgabe umgeleitet. Mit dem Befehl 2> wird die Fehlerausgabe umgeleitet. W├╝rden wir also schreiben if ping -c1 $1 2> /dev/null w├╝rde er keine Fehlermeldungen mehr anzeigen, weil diese in /dev/null landet. Aber jegliche normale Ausgabe w├╝rde wieder auf dem Bildschirm erscheinen. Also m├╝ssen wir erst die Standardausgabe auf /dev/null lenken und dem Programm dann sagen dass die Fehlermeldungen auch dorthin geschickt werden sollen, wohin die Standardausgabe schreibt. Das ist dann der obige Befehl if ping -c1 $1 > /dev/null 2>&1.

2>&1 bedeutet Fehlerausgabe in Standardausgabe leiten und diese zeigt schon ja auf /dev/null.

Das vollst├Ąndig funktionsf├Ąhige script sieht dann wie folgt aus:

#!/bin/sh
if ping -c1 $1 > /dev/null 2>&1
then
  echo "Der Zielrechner ist online"
else
  echo "Der Zielrechner ist offline"
fi

Nun k├Ânnte man das Script aber noch etwas benutzerfreundlicher gestalten, denn was passiert wenn man vergisst einen hostnamen einzugeben? Richtig das Programm erwidert "Der Zielrechner ist offline". Es muss also eine M├Âglichkeit geben abzufangen ob etwas eingegeben wurde oder nicht und falls keine Eingabe erfolgt ist einen Hinweis auszugeben.
 
Das Problem kann man z.B. mit der Case Anweisung l├Âsen, Alternativ auch mit einer If Anweisung dazu aber zum Ende kurz mehr. Diese ist wie folgt aufgebaut:

case Pr├╝fwert in
Wert1)
   Befehl1
   ...
   ;;
Wert2)
   Befehl2
   ...
   ;;
*)
   Befehl3
   ...
   ;;
esac
   
Pr├╝fwert wird auf die Werte die ich darunter angegeben habe hier Wert1, Wert2 und * ├╝berpr├╝ft und f├╝hrt dann die dazugeh├Ârigen Befehl aus ist Pr├╝fwert weder Wert1 noch Wert2 so werden die Befehle bei * ausgef├╝hrt. In unserem Script sieht das dann wie folgt aus.



#!/bin/sh
case $# in
1)
        if ping -c1 $1 > /dev/null 2>&1
        then
          echo "Der Zielrechner ist online"
        else
          echo "Der Zielrechner ist offline"
        fi
        ;;
*)
        echo "Usage: testscript.sh host"
        ;;
esac

die einzige Unklarheit die hier jetzt aufkommen sollte ist das $#. Diese Variable steht f├╝r die Anzahl der an das Script ├╝bergebenen Argumente. Rufe ich also das Script auf, ohne einen Host dahinter zu schreiben hat $# logischerweise den Wert 0 und das Ergebnis w├Ąre die Ausgabe "Usage testscript.sh host". Gebe ich einen Host ein so hat $# den Wert 1 und der Befehlszweig bei 1 wird ausgef├╝hrt. F├╝r jeden weiteren Wert landet er wieder bei * und es wird die Fehlermeldung angezeigt.

Jetzt ist unser Script eigentlich fertig und weist den Benutzer auch auf den fehlenden Host hin falls dieser nicht angegeben wird. Als letzten Abschluss k├Ânnte man jetzt noch einbauen dass man mehrere Hosts angeben kann und bei der Ausgabe auch noch einmal der Host erw├Ąhnt wird. Hier kommt die schon oben erw├Ąhnte For Konstruktion zum tragen. Diese ist aber hier keine Z├Ąhlschleife wie in anderen Programmiersprachen, sondern l├Ąuft eine bestimmte Anzahl an ├╝bergebenen Elementen durch.

for Wert in param1 param2 param3
do
  Befehl
done
 
Bei dieser Konstruktion wird die Schleife 3x durchlaufen, da ich 3 Argumente angegeben habe und die Variable Wert w├╝rde nacheinander die Werte von param1, param2 und param3 annehmen und w├╝rde dann aufh├Âren. Die folgende Konstruktion

for wert in param1
do
  Befehl
done

w├╝rde daher nur einmal durchlaufen. Unser Script soll so arbeiten, dass alle Hosts die als Parameter ├╝bergeben werden gesucht werden und eine Meldung mit dem entsprechenden Host erscheint.

Also f├╝gen wir wieder etwas mehr in das Script ein, fertig sieht es wie folgt aus.

#!/bin/sh

case $# in
0)
        echo "Usage: testscript.sh host"
        ;;
*)
        for host in $@
        do
          if ping -c1 $host > /dev/null 2>&1
          then
            echo "Der Zielrechner $host ist online"
          else
            echo "Der Zielrechner $host ist offline"
          fi
        done
        ;;
esac

Hier wurde die case Abfrage so abge├Ąndert, dass nur noch eine Fehlermeldung erscheint wenn kein host eingegeben wurde und sowie einer oder mehrere ├╝bergeben wurden, so wird unser ping Test durchgef├╝hrt. In der For Konstruktion erscheint jetzt oben das $@ dieses ist eine weitere Skriptvariable, sie enth├Ąlt alle ├╝bergeben Parameter. Rufe ich also /home/gilke/testscipt edv1 edv2 edv3 edv4 auf so hat $@ den Wert "edv1 edv2 edv3 edv4" das macht es nat├╝rlich einfach alle ├╝bergeben Argumente im For Konstrukt abzuhandeln. F├╝hren wir also unser script jetzt erneut aus.

[gilke@sonny gilke]$ /home/gilke/testscript.sh edv1 edv2 edv3 edv4
Der Zielrechner edv1 ist online
Der Zielrechner edv2 ist online
Der Zielrechner edv3 ist online
Der Zielrechner edv4 ist offline
[gilke@sonny gilke]$

Und wie man an dem Ergebnis sieht es funktioniert einwandfrei. Ein weiteres Schmankerl w├Ąre nat├╝rlich eine Abfrage ob der Benutzer nicht doch noch einen weiteren Host ├╝berpr├╝fen will oder ob er das Programm bzw. Script an dieser Stelle verlassen will. Eine Eingabe eines Benutzers f├Ąngt man mit dem Befehl read ab.

Gebe ich also im Script folgendes ein:

echo "Geben Sie den Host ein. "
read host

wird auf dem Bildschirm folgendes erscheinen.
"Geben Sie den Host ein." Und er w├╝rde auf eine Eingabe warten. Dieses wollen wir aber solange wiederholen bis der User sagt Ende. Also brauchen wir eine Wiederholkonstruktion.

Somit m├╝ssen wir folgendes schreiben. Bei den Abfragen ist immer darauf zu achten dass nach und vor der eckigen Klammer ein Leerzeichen sein muss, gleiches gilt f├╝r den Vergleichsoperator.

until [ "$eingabe" = n ] oder while [ "$eingabe" = j ]
do  
  echo "Wollen sie noch einen host pr├╝fen j/n "  
  read eingabe
done

Das m├╝ssen wir jetzt also irgendwie auf unser script ├╝bertragen, mit der noch folgenden Eingabe des neuen Host. Hier jetzt das komplett fertige Script.


#!/bin/sh

case $# in
0)
        echo "Usage testscript host"
        ;;
*)
        for host in $@
        do
          if ping -c1 $host > /dev/null 2>&1
          then
            echo "Der Zielrechner $host ist online"
          else
            echo "Der Zielrechner $host ist offline"
          fi
        done
        until [ "$eingabe" = n -o "$eingabe" = N]
        do
        echo "Wollen Sie noch weitere Hosts scannen j/n ? "
        read eingabe
        if [ "$eingabe" = j -o "$eingabe" = J ]
        then
          echo "Geben Sie die zu scannenden Hosts ein, jeweils getrennt durch ein Leerzeichen: "
          read newhosts
          for newhost in $newhosts
          do
            if ping -c1 $newhost > /dev/null 2>&1
            then
              echo "Der Zielrechner $newhost ist online"
            else
              echo "Der Zielrechner $newhost ist offline"
            fi
          done
        fi
        done
        ;;
esac
 
Die beiden Eingabeabfragen

if [ "$eingabe" = j -o "$eingabe" = J ]
until [ "$eingabe" = n -o "$eingabe" = N ]

enthalten jetzt jeweils eine 2. Abfrage die mit einem -o angeh├Ąngt wurde. Dieses -o steht f├╝r nichts weiter als eine logische Oder Verkn├╝pfung. Sollte der User n├Ąmlich ein "J" anstelle eines "j" eingeben so w├╝rde das Programm nicht reagieren weil es auf ein kleines "j" wartet. Daher muss an dieser Stelle Gro├č- und Kleinschreibung abgefragt werden. Die 2. logische Verkn├╝pfung die noch existiert, ist das logische Und, da wird anstelle des -o ein -a geschrieben. W├╝rde hier aber keinen Sinn ergeben da ich ja nicht gleichzeitig ein gro├čes und ein kleines "j" bzw. "n" eingeben kann.

Hier noch einmal das Script mit einer If Anweisung, da sich das Case hier noch nicht wirklich gelohnt hat.

#!/bin/sh

if [ $# = 0 ]
then echo "Usage testscript host"
else
        for host in $@
        do
          if ping -c1 $host > /dev/null 2>&1
          then
            echo "Der Zielrechner $host ist online"
          else
            echo "Der Zielrechner $host ist offline"
          fi
        done
        until [ "$eingabe" = n -o "$eingabe" = N ]
        do
        echo "Wollen Sie noch weitere Hosts scannen j/n ? "
        read eingabe
        if [ "$eingabe" = j -o "$eingabe" = J ]
        then
          echo "Geben Sie die zu scannenden Hosts ein, jeweils getrennt durch ein Leerzeichen: "
          read newhosts
          for newhost in $newhosts
          do
            if ping -c1 $newhost > /dev/null 2>&1
            then
              echo "Der Zielrechner $newhost ist online"
            else
              echo "Der Zielrechner $newhost ist offline"
            fi
          done
        fi
        done
fi

Fragen, Anregungen und Kritik k├Ânnt ihr Hier loswerden.
« Letzte ├änderung: 27. Juni 2005, 19:38:23 von CaBaL »
|| HT4U ||

Offline Dennis

  • HT4U.net Redakteur
  • 64-Bit-Prozessor
  • *****
  • Beitr├Ąge: 5939
  • Geschlecht: M├Ąnnlich
  • Killerspiele-Spieler!
    • Profil anzeigen
    • Meine :)
« Letzte ├änderung: 21. Mai 2005, 13:47:20 von CaBaL »
|| HT4U ||

Offline DrizZt

  • Windows-BIOS-Flasher
  • ***
  • Beitr├Ąge: 67
  • Pfff!
    • Profil anzeigen
Re:Diskussion zur Scriptprogrammierung unter Linux
« Antwort #2 am: 14. Juni 2005, 13:18:33 »
lang aber gut  :D

ChrisG1

  • Gast
Re: Scriptprogrammierung unter Linux
« Antwort #3 am: 27. Oktober 2014, 10:54:26 »
Super Anleitung !
Newbies bedanken sich gerne...