Die Arbeit in der Konsole bietet unter anderem durch die Möglichkeit von Scripts eine komfortable Möglichkeit wiederkehrende Aufgaben zu automatisieren. Dabei wird eine Datei erstellt, die eine Reihe von Befehlen enthält, die sequenziell ausgeführt werden.
Hier sei nochmals auf den Unterschied zwischen den Begriffen Shell und Bash hingewiesen. Eine Shell ist ein Programm,
welches uns eine Kommandozeileninterface zur Verfügung stellt. Die Bash ( Bourne Again SHell) ist
eine der am weitesten verbreiteten Shells unter Linux.
Die Beispiele und Erklärungen hier gehen von der Verwendung der Bash als Shell aus. Sie können dies in der Konsole mit dem Befehl
echo $SHELL prüfen.
Unser erstes Script ist - wie könnte es anders sein - helloworld.sh.
Erstellen Sie diese Datei in ihrem Home-Verzeichnis in einem Unterverzeichnis namens ~/bin.
Die Datei hat folgenden Inhalt:
#!/bin/bash HEUTE=$(date) echo "Hello World!" echo "Heute ist $HEUTE"
Um dieses Script ausführen zu können, müssen wir die Berechtigung noch korrekt setzten. Scripts benötigen
das Recht eXecute. Setzen Sie dieses mit dem Befehl chmod.
Sie können das Script nun jederzeit durch Eingabe des Scriptnamens "als Befehl" ausführen. Das funktioniert
deshalb, weil wir das Script im Verzeichnis ~/bin abgespeichert haben und dieses Verzeichnis standardmäßig neben den
üblichen Systempfaden verwendet wird um nach Befehlen (und Scripts) zu suchen.
Die Ausgabe sollte in etwa so aussehen:
your-login@your-host:~$ helloworld.sh Hello World! Heute ist Mon, 30 Mar 26 14:48:54 +0200
Das Script, Zeile für Zeile:
Zeile #1: #!/bin/bash ist der so genannte shebang. Jedes Script, das mit
einem Interpreter gestartet werden muss, wird mit einem shebang gestartet.
Dadurch "weiß" die Shell welches Programm für die Interpretation der Befehle genutzt werden muss.
Zeile #2: HEUTE=$(date)
Es wird eine Variable mit dem Namen HEUTE definiert. Der Wert der Variable wird durch die Ausgabe eines Befehls "befüllt".
Dies wird dadurch erreicht, indem Sie die Schreibweise $( ... ) verwenden. Alles was zwischen den Klammern
steht, wird als Befehl gewertet und ausgeführt. Die Ausgabe, die dieser Befehl liefert wird anschließend in die Variable gespeichert.
Zeile #3: echo "Hello World!"
Diese Zeile funktioniert exakt so, wie sie auch bei der normalen Eingabe in der Konsole funktioniert. Es wird der Text zwischen den " ausgegeben.
Zeile #4: echo "Heute ist $HEUTE"
Ähnliche Funktion wie in Zeile 3. Nur geben wir hier den Inhalt der Variablen $HEUTE im Text aus.
helloworld.sh Wie lautet dein Name? Joachim Hallo Joachim! Heute ist Mittwoch, 21. August, 11:23
echo DummyUser | helloworld.sh Hallo DummyUser! Heute ist Mittwoch, 21. August, 11:24
cat ~/bin/helloworld.sh #!/bin/bash HEUTE=$(date +"%A, %d. %B, %H:%M") read -p "Wie lautet dein Name? " NAME echo "Hallo $NAME!" echo "Heute ist $HEUTE"
Bash-Scripting ist hervorragend dafür geeignet einfache Aufgaben zu automatisieren. Ein Bash-Script ist dann
die beste Wahl wenn Sie die Befehle die abgearbeitet werden sollen auch manuell in die Konsole eingeben
könnten oder müssten. Diese Scripts unterstützen auch einige Konzepte die man aus gängigen Programmiersprachen
gewohnt ist wie Bedinungen, Schleifen, Variablen usw.
Ist Ihre Anforderung jedoch komplexer ist vermutlich eine andere Programmiersprache besser dafür geeignet.
Wie in jedem Quellcode ist es auch bei Scripts von Vorteil wenn man die Funktionsweise kommentiert. Auch hier
gilt (wie in allen Programmiersprachen): kommentieren Sie keine offensichtlichen Programmblöcke sondern verwenden
Sie Kommentare dort, wo sie einen Mehrwert haben.
Als Kommentarzeichen wird im Bash-Scripting # verwendet. Alles was in einer Zeile nach
dem # kommt wird daher als Kommentar betrachtet.
Weiter oben haben wir bereits eine Variable (HEUTE) verwendet. Folgende Punkte sind bei der Verwendung von Variablen
zu beachten:
- Variablenbezeichnungen dürfen nur aus Buchstaben, Zahlen und _ bestehen
- Das erste Zeichen muss ein Buchstabe oder _ sein
- Es dürfen keine Sonder- oder Leerzeichen verwendet werden
- Groß- und Kleinschreibung wird unterschieden (case-sensitive)
- Bei der Zuweisung verwendet man nur den Variablennamen - ohne $
- Bei der Verwendung der Variable wird ein $ vor den Variablennamen notiert.
Bedingungen werden mit dem if Statement definiert. Die Syntax lautet
if [ condition ]; then statement elif [ condition ]; then statement else do this by default fiACHTUNG - achten Sie sorgfälltig auf die Leerzeichen bei den Bedingungen und auf den ; nach der Bedingung!
| = | Vergleicht 2 Werte (Texte) miteinander. True, wenn der erste Wert gleich dem zweiten Wert ist. | if [ "$NAME" = "admin" ]; |
| != | Vergleicht 2 Werte miteinander. True, wenn der erste Wert NICHT gleich dem zweiten Wert ist. | if [ "$NAME" != "" ]; |
| -eq | eq = Equal; Vergleicht 2 Ganzzahlen miteinander. True, wenn der erste Wert gleich dem zweiten Wert ist. | if [ $NR -eq 2 ]; |
| -ne | ne = Not equal; Vergleicht 2 Ganzzahlen miteinander. True, wenn der erste Wert NICHT gleich dem zweiten Wert ist. | if [ $NE -ne 10 ]; |
| -lt | lt = less than; True, wenn der erste Wert kleiner als der zweite Wert ist. | if [ $INDEX -lt 10 ]; |
| -gt | gt = greater than; True, wenn der erste Wert größer als der zweite Wert ist. | if [ $INDEX -gt 5 ]; |
| -a | a = and; Verknüpft zwei Bedingungen mit UND | if [ $a -gt 60 -a $a -lt 100 ]; |
| -o | o = or; Verknüpft zwei Bedingungen mit ODER | if [ $NAME -eq "admin" -o $NAME -eq "root" ]; |
cat ~/bin/helloworld.sh #!/bin/bash # helloworld.sh, Version 2.0, 21.08.2024 # ----------------------------------------------- # Einfaches Shellscript um verschiedene Grundkonzepte wie Variablen, User Ein- und Ausgaben # und dergleichen einzusetzen. # # Version 1.0 um Kommentare und Sprachauswahl ergänzt # # Einlesen des aktuellen Datums im geforderten Format: # %A = Wochentag # %d = Tag im Monat # %B = Monat # %H = Stunde im 24-Stundenformat # %M = Minuten HEUTE=$(date +"%A, %d. %B, %H:%M") # Auswahlmöglichkeit der Sprache read -p "Wählen Sie ihre bevorzugte Sprache / Please choose your preferred language [de|en] " LANG # Standard wäre de, wenn nichts eingegeben wurde if [ -z "$LANG" ]; then LANG="de" fi if [ "$LANG" != "de" ] && [ "$LANG" != "en" ]; then echo "Ungültige Sprachauswahl. de für deutsch oder en für englisch" echo "Invalid language. de to use german, en to use english" exit 1 fi if [ "$LANG" == "de" ]; then PROMPTNAME="Wie lautet dein Name?" HELLOSTR="Hallo" TODAYSTR="Heute ist" fi if [ "$LANG" == "en" ]; then PROMPTNAME="What's your name?" HELLOSTR="Hello" TODAYSTR="Today is" fi # Einlesen eines Namens für die anschließende Begrüßung read -p "$PROMPTNAME " NAME echo "$HELLOSTR $NAME!" echo "$TODAYSTR $HEUTE"
i=1 while [ $i -le 10 ] ; do echo "$i" (( i += 1 )) doneSyntax einer for Schleife
for i in {1..5}
do
echo $i
done
In diesem Beispiel wird die Schleife aus einer numerischen Liste zwischen 1 und 5 generiert.USERS="root nobody someuser"
for i in $USERS
do
echo "Prüfe etwas bezüglich des Users $i"
done
Die Ausgabe eines Befehls kann ebenso dafür verwendet werden
i = 1
for LINE in $(head /etc/passwd)
do
echo "Zeile $i in /etc/passwd: $LINE"
(( i += 1 ))
done
Oder auch Dateinamen aufgrund eines Ausdrucks
i = 1
for FILE in /etc/*.conf
do
echo "Datei mit Endung .conf in /etc: $FILE"
done
cat ~/bin/loops.sh #!/bin/bash # loops.sh, Version 1.0, 21.08.2024 # ----------------------------------------------- # Einfaches Shellscript um die Konzepte der verschiedenen # Schleifen ausprobieren zu können # ## Endlosschleife mit der Möglichkeit über den Befehl "id" zu prüfen # ob ein eingegebener User im System angelegt ist # Schleife wird beendet, wenn kein Username eingegeben wurde while true; do read -p "Username [Leer = Abbruch]: " USER if [ "$USER" == "" ]; then break; fi if id $USER > /dev/null 2>&1; then echo "User $USER gefunden" else echo "User $USER nicht gefunden" fi done ## Countdown mit individueller Eingabe durch den Benutzer read -p "Geben Sie den Startwert für den Countdown ein: " COUNTDOWN if ! [[ "$COUNTDOWN" =~ ^[0-9]+$ ]]; then echo "Ungültige Eingabe. Bitte nur Zahlen" exit 1 fi echo "Der Countdown beginnt bei $COUNTDOWN" while [ $COUNTDOWN -ge 0 ]; do echo $COUNTDOWN ((COUNTDOWN--)) done echo "Houston, we have a lift-off!" ## Iteration durch 3 Namen mit denen helloworld.sh aufgerufen wird NAMES="Gandalf Frodo Bilbo" LANG="de" for N in $NAMES; do # Das Script helloworld.sh erwartet zwei Eingaben. # 1: Sprache (de|en) # 2: Name # Daher werden beide Werte mit echo ausgegeben. Die Option -e sorgt dafür # dass Sonderzeichen wie ein Zeilenumbruch mit \n interpretiert werden. echo -e "$LANG\n$N" | helloworld.sh done
test -e /pfad/gibt-es-nicht || echo "Den Pfad gibt es nicht!"Wenn wir diese Tests in einem if Statement verwenden können wir auf den Befehl test verzichten, die Bedingung prüft dabei den Exit-Code
# Wird ein ! vor den Test gestellt, wird die Überprüfung negiert
if [ ! -e /pfad/gibt-es-nicht ]; then
echo "Den Pfad gibt es nicht!"
fi
cat ~/bin/tests.sh #!/bin/bash # tests.sh, Version 1.0, 21.08.2024 # ----------------------------------------------- # Einfaches Shellscript um die Konzepte der verschiedenen # tests wie auf vorhandensein, Berechtigung usw. # anzuwenden # ## Prüfen, ob ein Verzeichnis vorhanden ist und wenn nicht, erstellen. DIR="$HOME/demo-condition" if ! [ -d "$DIR" ]; then echo "Verzeichnis $DIR noch nicht vorhanden. Es wird erstellt." mkdir $DIR || exit 1 fi ## Prüfen der Leseberechtigung auf alle Dateien im Verzeichnis /etc rTrue=0 rFalse=0 for FILE in /etc/* do if [ -r $FILE ]; then (( rTrue += 1 )) else echo "Kein Lesezugriff auf Datei $FILE" (( rFalse += 1 )) fi done echo "Lesezugriff gewährt: $rTrue; verweigert: $rFalse"
cat ~/bin/backup.sh #!/bin/bash # backup.sh, Version 1.0, 21.08.2024 # ----------------------------------------------- # Ein Shellscript welches eine tägliche Sicherung eines speziellen # Verzeichnisses macht. # # Definieren der Variablen SOURCE="$HOME/example-data" TARGET="$HOME/backup" D=$(date +"%Y%m%d") FILE="example-data-$D.tar.gz" BACKUPPATH="$TARGET/$FILE" # Prüfen, ob es das zu sichernde Verzeichnis überhaupt gibt if ! [ -d $SOURCE ]; then echo "Das zu sichernde Verzeichnis $SOURCE ist nicht vorhanden" exit 1 fi # Zielverzeichnis erstellen, falls nicht vorhanden if ! [ -d $TARGET ]; then mkdir $TARGET || exit 2 fi # Prüfen, ob es für diesen Tab bereits eine Sicherung gibt if [ -e $BACKUPPATH ]; then read -p "Die Sicherung $FILE ist bereits vorhanden. Neu erstellen? [y|n]: " REMOVE if [ "$REMOVE" != "y" ]; then exit 0 fi rm $BACKUPPATH || exit 3 fi # Sicherung erstellen tar -czf $BACKUPPATH $SOURCE # Prüfen auf den Rückgabewert des tar Befehls. Dieser ist 0, wenn der Befehl erfolgreich war if [ $? -ne 0 ]; then MSG="Sicherung $FILE fehlgeschlagen" echo $MSG logger $MSG exit 100 fi # Protokollierung MSG="Sicherung $FILE erfolgreich" echo $MSG logger $MSG