Scroll to top

German (Deutsch) translation by Tatsiana Bochkareva (you can also view the original English article)

Shell-Skripte sind in der UNIX-Welt weit verbreitet. Sie eignen sich hervorragend, um sich wiederholende Aufgaben zu beschleunigen und die komplexe Ausführungslogik zu vereinfachen. Sie können so einfach wie eine Reihe von Befehlen sein oder komplexe Aufgaben orchestrieren. In diesem Tutorial erfahren Sie mehr über die Bash-Skriptsprache, indem Sie Schritt für Schritt ein Beispielskript schreiben.


Das Fizz-Buzz-Problem

Eine der besten Möglichkeiten, eine neue Sprache kennenzulernen, ist das Beispiel. Beginnen wir mit einem.

Das Fizz-Buzz-Problem ist sehr einfach. Es wurde berühmt, nachdem ein Programmierer namens Imran es als Interviewtest verwendete. Es stellt sich heraus, dass 90-99,5% der Kandidaten für einen Programmierjob einfach nicht in der Lage sind, das einfachste Programm zu schreiben. Imran nahm dieses einfache Fizz-Buzz-Spiel und bat die Kandidaten, es zu lösen. Viele folgten Imrans Beispiel, und heute ist es eine der am häufigsten gestellten Fragen für einen Programmierjob. Wenn Sie einstellen und eine Möglichkeit benötigen, 90% der Kandidaten zu filtern, ist dies ein großes Problem.

Hier sind die Regeln:

  • Nehmen Sie die Zahlen zwischen 1 und 100 und drucken Sie sie aus.
  • Wenn eine Zahl durch 3 teilbar ist, drucken Sie "Fizz" anstelle der Zahl.
  • Wenn es durch 5 teilbar ist, drucken Sie stattdessen "Buzz".
  • Wenn es sowohl durch 3 als auch durch 5 teilbar ist, drucken Sie "FizzBuzz".

Das ist alles dazu. Ich bin sicher, dass die meisten von Ihnen bereits die zwei oder drei if-Anweisungen visualisieren können, um dies zu lösen. Lassen Sie uns dies mit der Skriptsprache Bash durcharbeiten.


Shebang

Ein Shebang bezieht sich auf die Kombination der Hash- und Ausrufezeichen: #!. Der Programmlader sucht in der ersten Zeile des Skripts nach einem Shebang und verwendet den darin angegebenen Interpreter. Ein Shebang besteht aus der folgenden Syntax: #!interpreter[parameter]. Der Dolmetscher ist das Programm, mit dem unsere Sprache interpretiert wird. Für Bash-Skripte wäre das /bin/bash. Wenn Sie beispielsweise ein Skript in PHP erstellen und in der Konsole ausführen möchten, möchten Sie wahrscheinlich /usr/bin/php (oder den Pfad zur ausführbaren PHP-Datei auf Ihrem Computer) als Interpreter verwenden.

1
#!/usr/bin/php

2
<?php
3
phpinfo();

Ja, das wird tatsächlich funktionieren! Ist es nicht einfach? Stellen Sie einfach sicher, dass Ihre Datei zuerst ausführbar ist. Sobald Sie dies tun, gibt dieses Skript Ihre PHP-Informationen wie erwartet aus.

Tipp: Um sicherzustellen, dass Ihr Skript auf so vielen Systemen wie möglich funktioniert, können Sie im binbang /bin/env verwenden. Daher können Sie anstelle von /bin/bash /bin/env bash verwenden, was auf Systemen funktioniert, auf denen sich die ausführbare Bash-Datei nicht in /bin befindet.


Text ausgeben

Die Ausgabe eines Skripts entspricht erwartungsgemäß dem, was von Ihrem Befehl ausgegeben wird. Wenn wir jedoch explizit etwas auf den Bildschirm schreiben möchten, können wir echo verwenden.

1
#!/bin/bash

2
3
echo "Hello World"

Wenn Sie dieses Skript ausführen, wird "Hello World" in der Konsole gedruckt.

1
csaba@csaba ~ $ ./helloWorld.sh
2
Hello World
3
csaba@csaba ~ $

Einführung von Variablen

Wie bei jeder Programmiersprache können Sie beim Schreiben von Shell-Skripten Variablen verwenden.

1
#!/bin/bash

2
3
message="Hello World"
4
echo $message

Dieser Code erzeugt genau die gleiche "Hallo Welt" -Nachricht. Wie Sie sehen können, schreiben Sie zum Zuweisen eines Werts zu einer Variablen einfach ihren Namen - schließen Sie das Dollarzeichen davor aus. Seien Sie auch vorsichtig mit Leerzeichen; Zwischen dem Variablennamen und dem Gleichheitszeichen dürfen keine Leerzeichen stehen. Also message="Hello" statt message = 'Hello'

Wenn Sie eine Variable verwenden möchten, können Sie den Wert genau wie im Befehl echo verwenden. Wenn Sie dem Namen der Variablen ein $ voranstellen, wird der Wert zurückgegeben.

Tipp: In Bash-Skripten sind keine Semikolons erforderlich. Sie können sie in den meisten Fällen verwenden, aber seien Sie vorsichtig: Sie haben möglicherweise eine andere Bedeutung als erwartet.


Drucken der Zahlen zwischen 1 und 100

Wenn wir mit unserem Demo-Projekt fortfahren, müssen wir alle Zahlen zwischen 1 und 100 durchlaufen. Dazu müssen wir eine for-Schleife verwenden.

1
#!/bin/bash

2
3
for number in {1..100}; do

4
    echo $number
5
done

In diesem Beispiel gibt es einige neue Dinge, die es wert sind, erwähnt zu werden. Dabei werden übrigens alle Zahlen von 1 bis 100 einzeln gedruckt.

  • Die for-Syntax in Bash lautet: for VARIABLE in RANGE; do COMMAND done.
  • Die geschweiften Klammern verwandeln 1..100 in einen Bereich in unserem Beispiel. Sie werden auch in anderen Kontexten verwendet, die wir in Kürze überprüfen werden.
  • do und for sind eigentlich zwei separate Befehle. Wenn Sie zwei Befehle in einer einzigen Zeile platzieren möchten, müssen Sie sie irgendwie trennen. Eine Möglichkeit ist die Verwendung von Semikolon. Alternativ können Sie den Code auch ohne Semikolon schreiben, indem Sie do in die folgende Zeile verschieben.
1
#!/bin/bash

2
3
for number in {1..100}
4
do

5
    echo $number
6
done

Die erste Entscheidung

Jetzt, da wir wissen, wie alle Zahlen zwischen 1 und 100 gedruckt werden, ist es Zeit, unsere erste Entscheidung zu treffen.

1
#!/bin/bash

2
3
for number in {1..100}; do

4
    if [ $((number%3)) -eq 0 ]; then

5
        echo "Fizz"
6
    else

7
        echo $number
8
    fi

9
done

In diesem Beispiel wird "Fizz" für durch 3 teilbare Zahlen ausgegeben. Auch hier müssen wir uns mit etwas neuer Syntax befassen. Nehmen wir sie eins nach dem anderen.

  • if..then..else..fi - Dies ist die klassische Syntax für eine if-Anweisung in Bash. Natürlich ist der else-Teil optional - aber in diesem Fall für unsere Logik erforderlich.
  • if COMMAND-RETURN-VALUE; then... - if wird ausgeführt, wenn der Rückgabewert des Befehls Null ist. Ja, die Logik in Bash basiert auf Null, was bedeutet, dass Befehle, die erfolgreich ausgeführt werden, mit einem Code von 0 beendet werden. Wenn etwas schief geht, wird andererseits eine positive Ganzzahl zurückgegeben. Zur Vereinfachung: Alles andere als 0 wird als false angesehen.
  • Mathematische Ausdrücke in Bash werden durch doppelte Klammern angegeben. $((number%3)) gibt den verbleibenden Wert der Division der Variablen number durch 3 zurück. Bitte beachten Sie, dass wir $ nicht in Klammern verwendet haben - nur vor ihnen.

Sie fragen sich möglicherweise, wo sich der Befehl in unserem Beispiel befindet. Gibt es nicht nur eine Klammer mit einem seltsamen Ausdruck? Nun, es stellt sich heraus, dass [ tatsächlich ein ausführbarer Befehl ist. Probieren Sie die folgenden Befehle in Ihrer Konsole aus, um damit herumzuspielen.

1
csaba@csaba ~ $ which [
2
/usr/bin/[
3
csaba@csaba ~ $ [ 0 -eq 1 ]
4
csaba@csaba ~ $ echo $?
5
1
6
csaba@csaba ~ $ [ 0 -eq 0 ]
7
csaba@csaba ~ $ echo $?
8
0

Tipp: Der Exit-Wert eines Befehls wird immer in die Variable zurückgegeben ? (Fragezeichen). Es wird nach der Ausführung jedes neuen Befehls überschrieben.


Nach Buzz suchen

Bisher geht es uns gut. Wir haben "Fizz"; Jetzt machen wir den "Buzz" Teil.

1
#!/bin/bash

2
3
for number in {1..100}; do

4
    if [ $((number%3)) -eq 0 ]; then

5
        echo "Fizz"
6
    elif [ $((number%5)) -eq 0 ]; then

7
        echo "Buzz"
8
    else

9
        echo $number
10
    fi

11
done

Oben haben wir eine weitere Bedingung für die Teilbarkeit durch 5 eingeführt: die elif-Anweisung. Dies wird natürlich in else if übersetzt und ausgeführt, wenn der darauf folgende Befehl true (oder 0) zurückgibt. Wie Sie sehen können, werden die bedingten Anweisungen in [] normalerweise mit Hilfe von Parametern, wie -eq ausgewertet, was für "equals" steht.

Für die Syntax arg1 OP arg2 ist OP eine von -eq, -ne, -lt, -le, -gt oder -ge. Diese arithmetischen Binäroperatoren geben true zurück, wenn arg1 gleich, nicht gleich, kleiner als, kleiner oder gleich, größer als oder größer oder gleich arg2 ist. arg1 und arg2 können positive oder negative ganze Zahlen sein. - Bash-Handbuch

Wenn Sie versuchen, Zeichenfolgen zu vergleichen, können Sie das bekannte == Zeichen verwenden, oder sogar ein einzelnes Gleichheitszeichen reicht aus. != gibt true zurück, wenn die Zeichenfolgen unterschiedlich sind.


Aber der Code ist nicht ganz richtig

Bisher läuft der Code, aber die Logik ist nicht korrekt. Wenn die Zahl durch 3 und 5 teilbar ist, gibt unsere Logik nur "Fizz" aus. Lassen Sie uns unseren Code ändern, um die letzte Anforderung von FizzBuzz zu erfüllen.

1
#!/bin/bash

2
3
for number in {1..100}; do

4
    output=""
5
    if [ $((number%3)) -eq 0 ]; then

6
        output="Fizz"
7
    fi

8
    if [ $((number%5)) -eq 0 ]; then

9
        output="${output}Buzz"
10
    fi

11
    if [ -z $output ]; then

12
        echo $number
13
    else

14
        echo $output;
15
    fi

16
done

Auch hier mussten wir einige Änderungen vornehmen. Am bemerkenswertesten ist die Einführung einer Variablen und gegebenenfalls die Verkettung von "Buzz". Zeichenfolgen in Bash werden normalerweise zwischen doppelten Anführungszeichen (") definiert. Einfache Anführungszeichen sind ebenfalls verwendbar, aber zur einfacheren Verkettung sind doppelte Anführungszeichen die bessere Wahl. Innerhalb dieser doppelten Anführungszeichen können Sie auf Variablen verweisen: some text $variable some other text" ersetzt $variable durch seinen Inhalt. Wenn Sie Variablen mit Zeichenfolgen ohne Leerzeichen verketten möchten, ziehen Sie es möglicherweise vor, den Namen der Variablen in geschweifte Klammern zu setzen. In den meisten Fällen, wie bei PHP, müssen Sie dies nicht tun, aber es hilft sehr, wenn es um die Lesbarkeit des Codes geht.

Tipp: Sie können leere Zeichenfolgen nicht vergleichen. Das würde einen fehlenden Parameter zurückgeben.

Da Argumente in [ ] als Parameter für "[" behandelt werden, müssen sie sich von einer leeren Zeichenfolge unterscheiden. Obwohl dieser Ausdruck logisch ist, gibt er einen Fehler aus: [$output! = ""]. Aus diesem Grund haben wir [ -z  $output] verwendet, das true zurückgibt, wenn der String eine Länge von Null hat.


Extraktionsmethode für logischen Ausdruck

Eine Möglichkeit, unser Beispiel zu verbessern, besteht darin, den mathematischen Ausdruck aus den if-Anweisungen wie folgt in Funktionen zu extrahieren:

1
#!/bin/bash

2
3
function isDivisibleBy {
4
    return $(($1%$2))
5
}
6
7
for number in {1..100}; do

8
    output=""
9
    if isDivisibleBy $number 3; then

10
        output="Fizz"
11
    fi

12
    if isDivisibleBy $number 5; then

13
        output="${output}Buzz"
14
    fi

15
    if [ -z $output ]; then

16
        echo $number
17
    else

18
        echo $output;
19
    fi

20
done

Wir haben die Ausdrücke genommen, um den Rest mit Null zu vergleichen, und sie in eine Funktion verschoben. Darüber hinaus haben wir den Vergleich mit Null eliminiert, weil Null für uns wahr bedeutet. Wir müssen nur den Wert aus dem mathematischen Ausdruck zurückgeben - sehr einfach!

Tipp: Die Definition einer Funktion muss vor dem Aufruf erfolgen.

In Bash können Sie eine Methode als Funktion function func_name { commands; }. Optional gibt es eine zweite Syntax zum Deklarieren von Funktionen: func_name () { commands; }. Wir können also die Zeichenfolge und function löschen und nach dem Namen "()" hinzufügen. Ich persönlich bevorzuge diese Option, wie im obigen Beispiel veranschaulicht. Es ist expliziter und ähnelt traditionellen Programmiersprachen.

Sie müssen die Parameter für eine Funktion in Bash nicht angeben. Das Senden von Parametern an eine Funktion erfolgt durch einfaches Auflisten nach dem durch Leerzeichen getrennten Funktionsaufruf. Setzen Sie keine Kommas oder Klammern in den Funktionsaufruf - es wird nicht funktionieren.

Empfangene Parameter werden Variablen automatisch nach Nummer zugewiesen. Der erste Parameter geht zu $1, der zweite zu $2 und so weiter. Die spezielle Variable $0 bezieht sich auf den Dateinamen des aktuellen Skripts.

Lass uns mit Parametern spielen

1
#!/bin/bash

2
3
function exampleFunc {
4
    echo $1
5
    echo $0
6
    IFS="X"
7
    echo "$@"
8
    echo "$*"
9
}
10
11
exampleFunc "one" "two" "three"

Dieser Code erzeugt die folgende Ausgabe:

1
csaba@csaba ~ $ ./parametersExamples.sh
2
one
3
./parametersExamples.sh
4
one two thre
5
oneXtwoXthre

Lassen Sie uns die Quelle Zeile für Zeile analysieren.

  • Die letzte Zeile ist der Funktionsaufruf. Wir nennen es mit drei String-Parametern.
  • Die erste Zeile nach dem Shebang ist die Funktionsdefinition.
  • Die erste Zeile in der Funktion gibt den ersten Parameter aus: "Eins". So weit so einfach.
  • In der zweiten Zeile wird der Dateiname des aktuellen Skripts ausgegeben. Wieder sehr einfach.
  • In der dritten Zeile wird das Standardzeichentrennzeichen in den Buchstaben "X" geändert. Standardmäßig ist dies " " (ein Leerzeichen). So weiß Bash, wie die Parameter getrennt sind.
  • Die vierte Zeile gibt eine spezielle Variable aus, $@. Es repräsentiert alle Parameter als ein einziges Wort, genau wie im Funktionsaufruf angegeben.
  • Die letzte Zeile gibt eine weitere spezielle Variable aus, $*. Es stellt alle Parameter dar, die einzeln genommen und mit dem ersten Buchstaben der IFS-Variablen verknüpft werden. Deshalb ist das Ergebnis oneXtwoXthre.

Zurückgeben von Zeichenfolgen aus Funktionen

Wie bereits erwähnt, können Funktionen in Bash nur Ganzzahlen zurückgeben. Daher wäre das Schreiben der return "a string" ein ungültiger Code. In vielen Situationen benötigen Sie jedoch mehr als nur eine Null oder eine Eins. Wir können unser FizzBuzz-Beispiel so umgestalten, dass wir in der for-Anweisung nur einen Funktionsaufruf ausführen.

1
#!/bin/bash

2
3
function isDivisibleBy {
4
    return $(($1%$2))
5
}
6
7
function fizzOrBuzz {
8
    output=""
9
    if isDivisibleBy $1 3; then

10
        output="Fizz"
11
    fi

12
    if isDivisibleBy $1 5; then

13
        output="${output}Buzz"
14
    fi

15
    if [ -z $output ]; then

16
        echo $1
17
    else

18
        echo $output;
19
    fi
20
}
21
22
for number in {1..100}; do

23
    fizzOrBuzz $number
24
done

Nun, das ist der erste Schritt. Wir haben gerade den gesamten Code in eine Funktion namens fizzOrBuzz extrahiert und dann $number durch $1 ersetzt. Alle Ausgaben erfolgen jedoch in der Funktion fizzOrBuzz. Wir möchten aus der for-Schleife eine echo-Anweisung ausgeben, damit wir jeder Zeile eine andere Zeichenfolge voranstellen können. Wir müssen die Ausgabe der fizzOrBuzz-Funktion erfassen.

1
#[...]

2
for number in {1..100}; do

3
    echo "-`fizzOrBuzz $number`"
4
    fizzBuzzer=$(fizzOrBuzz $number)
5
    echo "-${fizzBuzzer}"
6
done

Wir haben unsere for-Schleife nur ein wenig aktualisiert (keine weiteren Änderungen). Wir haben jetzt alles zweimal auf zwei verschiedene Arten wiederholt, um die Unterschiede zwischen den beiden Lösungen für dasselbe Problem zu veranschaulichen.

Die erste Lösung, um die Ausgabe einer Funktion oder eines anderen Befehls zu erfassen, ist die Verwendung von Backticks. In 99% der Fälle funktioniert dies einwandfrei. Sie können eine Variable in Backticks einfach anhand ihrer Namen referenzieren, wie wir es mit $number getan haben. Die ersten Zeilen der Ausgabe sollten nun wie folgt aussehen:

1
csaba@csaba ~/Personal/Programming/NetTuts/The Basics of BASH Scripting/Sources $ ./fizzBuzz.sh
2
-1
3
-1
4
-2
5
-2
6
-Fizz
7
-Fizz
8
-4
9
-4
10
-Buzz
11
-Buzz
12
-Fizz
13
-Fizz
14
-7
15
-7

Wie Sie sehen können, ist alles dupliziert. Gleiche Ausgabe.

Für die zweite Lösung haben wir uns entschieden, zuerst den Rückgabewert einer Variablen zuzuweisen. In dieser Zuweisung haben wir $() verwendet, das in diesem Fall das Skript gabelt, den Code ausführt und seine Ausgabe zurückgibt.


&semi;, && und ||

Erinnerst du dich, dass wir hier und da Semikolon verwendet haben? Sie können verwendet werden, um mehrere Befehle auszuführen, die in derselben Zeile geschrieben sind. Wenn Sie sie durch Semikolons trennen, werden sie einfach ausgeführt.

Ein komplexerer Fall ist die Verwendung von && zwischen zwei Befehlen. Ja, das ist ein logisches UND; Dies bedeutet, dass der zweite Befehl nur ausgeführt wird, wenn der erste true zurückgibt (er wird mit 0 beendet). Das ist hilfreich; Wir können die if-Anweisungen in diese Abkürzungen vereinfachen:

1
#!/bin/bash

2
3
function isDivisibleBy {
4
    return $(($1%$2))
5
}
6
7
function fizzOrBuzz {
8
    output=""
9
    isDivisibleBy $1 3 && output="Fizz"
10
    isDivisibleBy $1 5 && output="${output}Buzz"
11
    if [ -z $output ]; then

12
        echo $1
13
    else

14
        echo $output;
15
    fi
16
}
17
18
for number in {1..100}; do

19
    echo "-`fizzOrBuzz $number`"
20
done

Da unsere Funktion isDivisibleBy einen korrekten Rückgabewert zurückgibt, können wir mit && die gewünschte Variable festlegen. Was nach && ist, wird nur ausgeführt, wenn die Bedingung true ist. Auf die gleiche Weise können wir || verwenden (Doppelpipe-Zeichen) als logisches ODER. Hier ist ein kurzes Beispiel.

1
csaba@csaba ~ $ echo "bubu" || echo "bibi"
2
bubu
3
csaba@csaba ~ $ echo false || echo "bibi"
4
false

5
csaba@csaba ~ $

Abschließende Gedanken

Das macht es also für dieses Tutorial! Ich hoffe, Sie haben eine Handvoll neuer Tipps und Techniken zum Schreiben Ihrer eigenen Bash-Skripte erhalten. Vielen Dank fürs Lesen und seien Sie gespannt auf weiterführende Artikel zu diesem Thema.