Hallo an alle. Dies ist eine Übersetzung aus dem RedHat RHCE Exam Preparation Book. Meiner Meinung nach ist es sehr zugänglich über die Bash-Grundlagen.
Shell-Skripte sind eine Wissenschaft für sich. Ohne auf Details von allem einzugehen, was „unter der Haube“ passiert, lernen Sie, wie Sie die Grundelemente zum Schreiben Ihrer eigenen Skripte verwenden und analysieren, was in Shell-Skripten von Drittanbietern passiert.

Grundlegendes zu Shell-Skripten
Tatsächlich ist ein Shell-Skript eine Liste von Befehlen, die nacheinander ausgeführt werden, sowie eine Logik, mit der Code nur unter bestimmten Bedingungen ausgeführt werden kann.
Um komplexe Shell-Skripte zu verstehen, wird empfohlen, mit grundlegenden Skripten zu beginnen.
Das Folgende ist ein sehr einfaches Skript:
Es enthält mehrere Elemente, die in allen Skripten verwendet werden sollten. Für den Anfang gibt es Shebang - dies ist die Zeile #! / Bin / Bash. Wenn das Skript über die übergeordnete Shell gestartet wird, wird eine Subshell geöffnet, in der die im Skript angegebenen Befehle ausgeführt werden.
Diese Befehle können auf verschiedene Arten interpretiert werden. Um genau zu verstehen, wie sie interpretiert werden sollen, wird Shebang verwendet. Im obigen Beispiel macht shebang deutlich, dass das Skript von der Bash-Shell ausgeführt werden muss.
Andere Schalen können ebenfalls angezeigt sein. Wenn Ihr Skript beispielsweise Perl-Code enthält, sollte shebang #! / Usr / bin / perl sein. Das Starten eines Skripts mit shebang ist eine gute Praxis. Wenn nicht angegeben, wird der Skriptcode von derselben Shell ausgeführt, die zum Ausführen des Skripts verwendet wird.
Unmittelbar nach dem Schebang gibt es einen Teil, in dem erklärt wird, worum es im Drehbuch geht. Ein paar Kommentarzeilen am Anfang jedes Szenarios sind eine gute Idee. In einem kurzen Skript ist oft klar, was es tut, aber je länger das Skript wird und je mehr Leute es schreiben und unterstützen, desto weniger wird klar, was die Autoren vorhaben.
Um diese Situation zu vermeiden, müssen Sie Kommentarzeilen hinzufügen, die mit jedem # -Zeichen beginnen. Kommentare können nicht nur in den ersten Zeilen, sondern auch am Anfang jedes Unterabschnitts des Skripts stehen. Dies wird sicherlich helfen, wenn Sie Ihr Skript in ein paar Monaten lesen!
Sie können auch nicht nur Unterabschnitte, sondern auch einzelne Zeilen kommentieren.
Egal in welcher Position es verwendet wird, alles vom # -Zeichen bis zum Ende der Zeile ist ein Kommentar.
Nach dem Kommentarblock befindet sich der Skriptkörper. Im obigen Beispiel sind dies mehrere Befehle, die nacheinander ausgeführt werden. Der Hauptteil des Shell-Skripts kann sich während der Entwicklung vergrößern.
Am Ende des Skripts habe ich die Anweisung
exit 0 eingefügt. Die exit-Anweisung teilt der übergeordneten Shell mit, ob das Skript erfolgreich war. Der Exit-Status des letzten Befehls im Skript ist der Exit-Status des Skripts selbst, es sei denn,
Exit 0 wird am Ende des Skripts verwendet.
Es ist nützlich zu wissen, dass Sie mit
exit arbeiten können , um der übergeordneten Shell mitzuteilen, wie die Dinge gelaufen sind.
In der übergeordneten Shell wird das Echo $? Mit dieser Option können Sie den Exit-Status des zuletzt ausgeführten Skripts abfragen.
Stellen Sie nach dem Erstellen des Skripts sicher, dass es ausgeführt werden kann. Der häufigste Weg, dies zu tun, besteht darin, ein Run-Bit darauf anzuwenden. Wenn der Name der Skriptdatei Hallo lautet, verwenden Sie den
Befehl chmod + x ./hello , um sie ausführbar zu machen.
Das Skript kann auch als Argument für den Befehl bash ausgeführt werden.
Geben Sie in diesem Fall
bash ./hello ein , um das Hallo-Skript auszuführen. Wenn das Skript als Argument für den Befehl bash ausgeführt wird, muss die Skriptdatei nicht ausführbar sein.
Sie können das Skript zwar überall speichern, aber wenn Sie es in einem Verzeichnis speichern möchten, das nicht in der Variablen $ PATH enthalten ist, müssen Sie es mit ./ vor dem Skriptnamen ausführen.
Geben Sie ./hello ein , um das Skript auszuführen, oder legen Sie es in dem Standardverzeichnis ab, das in der Variablen $ PATH enthalten ist, z. B. / usr / local / bin.
Sie können das Skript auch im Verzeichnis / bin ablegen. Geben Sie anschließend einfach den Dateinamen an einer beliebigen Stelle im Dateisystem ein, und das Skript wird ausgeführt.
BeispielErstellen Sie mit
vi / bin / datetime eine Datei mit dem Namen datetime im Verzeichnis / bin. Fügen Sie diesen Inhalt in die erstellte Datei ein:
Geben Sie nach dem Speichern der Datei
chmod + x / bin / datetime ein , um der Datei die Berechtigung zur Ausführung zu erteilen. Wechseln Sie beispielsweise mit dem
Befehl cd ~ in
Ihr Ausgangsverzeichnis und geben Sie einfach
datetime ein .
Gehen Sie zum Beispiel in das Verzeichnis cd ~ home und geben Sie einfach datetime ein.
[root@localhost ~]
Verwenden von Variablen und Eingaben
Bash-Skripte sind viel mehr als nur eine Liste von Befehlen, die nacheinander ausgeführt werden. Eines der schönen Dinge an Skripten ist, dass sie mit Variablen und Eingaben arbeiten können, um das Skript flexibel zu machen. In diesem Abschnitt erfahren Sie, wie Sie mit ihnen arbeiten.
Positionsparameter verwenden
Beim Ausführen des Skripts können Sie die Argumente verwenden. Ein Argument ist alles, was Sie hinter einen Skriptbefehl setzen. Argumente können verwendet werden, um das Skript flexibler zu gestalten. Nehmen Sie den Befehl
useradd lisa . In diesem Beispiel lautet der Befehl
useradd , und sein Argument
lisa gibt an, was zu tun ist.
Als Ergebnis eines solchen Befehls sollte ein Benutzer namens lisa erstellt werden.
Im Skript ist das erste Argument
$ 1 , das zweite Argument
$ 2 usw. Listing 1 zeigt, wie die Argumente verwendet werden können. Versuchen Sie, diesen Code auszuführen, indem Sie Benutzernamen als Parameter angeben.
Listing 1
Parameter bedeuten Dateneingabe vor dem Ausführen des Skripts. In diesem Fall habe ich
lisa ,
lori und
bob als Parameter nach dem Argument Skriptname angegeben:
[root@server1 ~]
Wenn Sie versucht haben, den Beispielcode auszuführen, stellen Sie möglicherweise fest, dass sein Inhalt nicht perfekt ist. Wenn Sie beim Ausführen des Skripts aus Listing 1 drei Argumente verwenden, funktioniert dies einwandfrei. Wenn Sie nur zwei Argumente verwenden, wird das dritte ohne den Wert $ 3 ausgegeben.
Wenn Sie vier Argumente verwenden, wird der vierte Wert (der in $ 4 gespeichert wird) niemals angezeigt. Wenn Sie also Argumente verwenden möchten, sollten Sie einen flexibleren Ansatz verwenden.
Listing 2:
Listing 2 zeigt zwei neue Elemente, die sich auf Argumente beziehen:- $ # Ist ein Zähler, der angibt, wie viele Argumente beim Ausführen des Skripts verwendet wurden.
- $ @ Ist eine Liste aller Argumente, die beim Ausführen des Skripts verwendet wurden.
Um die Argumente aufzulisten, die beim Ausführen dieses Skripts verwendet wurden, wird die
for- Schleife verwendet. In
for- Schleifen werden Anweisungen ausgeführt, solange die Bedingung erfüllt ist. In diesem Szenario bedeutet die Bedingung
für i in $ @ "für jedes Argument". Jedes Mal, wenn das Skript die Schleife durchläuft,
wird der Variable
$ i der Wert aus der Variablen
$ @ zugewiesen.
Solange also Argumente vorhanden sind, wird der Hauptteil des Skripts ausgeführt.
Der Hauptteil der for-Schleife beginnt immer mit
do und schließt
done , und die auszuführenden Befehle werden zwischen diesen beiden Schlüsselwörtern aufgelistet. Daher verwendet das Beispielskript
echo , um den Wert jedes Arguments anzuzeigen, und stoppt, wenn keine weiteren Argumente verfügbar sind.
Versuchen wir das Skript in Listing 2 in diesem Beispiel:- Geben Sie das Argument vi ein , um die Argumentdatei zu erstellen und den Inhalt aus dem Skript in Listing 2 in diese Datei zu kopieren.
- Speichern Sie die Datei und machen Sie sie ausführbar.
- Führen Sie den Befehl ./argument abc aus . Sie werden sehen, dass drei Zeilen angezeigt werden.
- Führen Sie den Befehl ./argument abcdef aus . Sie werden sehen, dass neben abc auch de f angezeigt wird.
Variablen
Eine Variable ist eine Bezeichnung, die verwendet wird, um eine bestimmte Stelle im Speicher anzugeben, die einen bestimmten Wert enthält. Variablen können statisch mit NAME = value oder dynamisch definiert werden. Es gibt zwei Lösungen zum dynamischen Definieren einer Variablen:
- Verwenden Sie das Schlüsselwort read in einem Skript, um Daten vom Benutzer anzufordern, der das Skript ausführt.
- Verwenden Sie die Befehlssubstitution, um das Ergebnis des Befehls zu verwenden und es einer Variablen zuzuweisen. Das Befehlsdatum +% d-% m-% y zeigt beispielsweise das aktuelle Datum im Format Tag-Monat-Jahr an. Um dies in einem Skript zu tun, können Sie HEUTE = $ (Datum +% d-% m-% y) verwenden . Um Befehle zu ersetzen, müssen Sie nur den Befehl, dessen Ergebnis Sie verwenden möchten, in die Klammern setzen.
Im vorherigen Abschnitt zu Positionsparametern haben Sie gelernt, wie Sie Variablen beim Ausführen eines Skripts Argumente zuweisen. In einigen Fällen kann es effizienter sein, Informationen anzufordern, wenn Sie feststellen, dass etwas Wesentliches fehlt. Das folgende Skript zeigt, wie das geht.
Listing 3. Beispielskript mit dem Befehl
read
Im Skript in Listing 3 wird der Operator
if ... then ... else ... fi verwendet, um die Existenz des Arguments
$ 1 zu testen. Dies erfolgt mit
test (test ist ein separater Befehl). Der Testbefehl kann auf zwei Arten * geschrieben werden:
test oder
[...] . Im Beispiel wird die Zeile
if [-z $ 1] ... ausgeführt, um den Test (check)
-z $ 1 anzuzeigen .
*
- eigentlich drei Quellen (ca. Übersetzer)-z Test prüft, ob
$ 1 existiert oder nicht. Mit anderen Worten, die Zeile
if [-z $ 1] prüft, ob
$ 1 leer ist. Dies bedeutet, dass beim Ausführen dieses Skripts keine Argumente angegeben wurden. In diesem Fall werden die Befehle nach der
then- Anweisung ausgeführt.
Bitte beachten Sie, dass es beim Schreiben des
Testbefehls in eckigen Klammern wichtig ist, Leerzeichen nach der öffnenden Klammer und vor der schließenden Klammer zu verwenden. Ohne Leerzeichen funktioniert der Befehl nicht.
Beachten Sie, dass die
then- Anweisung unmittelbar auf den
Test folgt. Dies ist möglich, weil ein Semikolon (;) verwendet wird. Das Semikolon ist ein Befehlstrennzeichen und kann eine neue Zeile in einem Skript ersetzen.
Die
then- Anweisung führt zwei Befehle aus: den
Echo- Befehl, der die Nachricht auf dem Bildschirm anzeigt, und den
Lesebefehl .
Der Befehl
read stoppt das Skript, damit Benutzereingaben verarbeitet und in der Variablen TEXT gespeichert werden können. Beim
Lesen von TEXT werden daher alle Benutzereingaben in die TEXT-Variable eingefügt, die später im Skript verwendet wird.
Der nächste Teil wird durch die
else-Anweisung dargestellt . Befehle nach der
else-Anweisung werden in allen anderen Fällen ausgeführt, was in diesem Fall "andernfalls, wenn das Argument angegeben wurde" bedeutet. Wenn ja, wird die TEXT-Variable bestimmt und der aktuelle Wert von
$ 1 zugewiesen.
Beachten Sie, wie die Variable definiert ist: Unmittelbar nach dem Namen der Variablen steht ein = -Zeichen gefolgt von $ 1. Beachten Sie, dass Sie beim Definieren von Variablen niemals Leerzeichen verwenden sollten.
Dann werden die if-Bedingungen mit dem
fi- Operator geschlossen. Nachdem die if-Bedingung erfüllt ist, wissen Sie sicher, dass die TEXT-Variable definiert ist und einen Wert hat. Die vorletzte Zeile des Skripts liest den Wert der TEXT-Variablen und ordnet diesen Wert mit dem Befehl
echo STDOUT zu. Beachten Sie, dass sich das Anfordern des aktuellen Werts einer Variablen auf den Namen der Variablen bezieht, beginnend mit dem $ -Zeichen davor.
Sie können dieses Beispiel üben, wenn Sie mit Eingaben arbeiten.- Öffnen Sie den Editor und erstellen Sie eine Datei mit dem Namen Text. Geben Sie den Inhalt des Codes in Listing 3 in diese Datei ein.
- Schreiben Sie die Datei auf die Festplatte und führen Sie chmod + x-Text aus , um sie ausführbar zu machen.
- Führen Sie das Skript aus, indem Sie ./text und ohne zusätzliche Argumente ausführen . Sie werden sehen, dass Sie zur Eingabe aufgefordert werden.
- Führen Sie das Skript mit " Hallo " als Argument aus (./text Hallo). Das Ergebnis zeigt in STDOUT "Sie haben den Text Hallo eingegeben" an.
Bedingungen und Schleifen verwenden
Wie Sie bereits gesehen haben, können bedingte Anweisungen in einem Skript verwendet werden. Diese bedingten Anweisungen werden nur ausgeführt, wenn eine bestimmte Bedingung erfüllt ist.
Es gibt mehrere bedingte Anweisungen und Schleifen in bash, die häufig verwendet werden.
- if ... then ... else - wird verwendet, um Code auszuführen, wenn eine bestimmte Bedingung erfüllt ist
- for - wird verwendet, um Befehle für einen Wertebereich auszuführen
- while - wird verwendet, um Code auszuführen, wenn eine bestimmte Bedingung erfüllt ist
- before - wird verwendet, um Code auszuführen, bis eine bestimmte Bedingung erfüllt ist
- case - wird verwendet, um eine begrenzte Anzahl spezifischer Werte auszuwerten
wenn dann sonst
Das
if then else-Konstrukt ist für die Bewertung bestimmter Bedingungen üblich. Sie haben bereits ein Beispiel mit ihm gesehen. Diese bedingte Anweisung wird häufig mit dem
Testbefehl verwendet . Mit diesem Befehl können Sie viele Dinge überprüfen: Zum Beispiel nicht nur, ob eine Datei vorhanden ist, sondern auch Dateien vergleichen, Ganzzahlen vergleichen und vieles mehr.
Weitere Informationen zum Test finden Sie in der Referenz mit dem Befehl man test.
Das grundlegende
if- Konstrukt ist
if ... then ... fi .
Es vergleicht eine Bedingung, wie im folgenden Beispiel gezeigt:
if [ -z $1 ] then echo no value provided fi
In Listing 3 haben Sie gesehen, wie Sie zwei Bedingungen bewerten können, einschließlich
else in einem Ausdruck. Listing 4 zeigt, wie mehrere Bedingungen von
if bis
else bewertet werden. Dies ist nützlich, wenn Sie viele verschiedene Werte überprüfen müssen.
Beachten Sie, dass in diesem Beispiel auch mehrere
Testbefehle verwendet werden.
Listing 4 : Beispiel mit
wenn dann sonst
|| und &&
Anstatt vollständige
if ... -Anweisungen zu schreiben
, können Sie die logischen Operatoren
|| verwenden sowie
&& .
|| ist ein logisches "ODER" und führt den zweiten Teil der Anweisung nur aus, wenn der erste Teil nicht wahr ist;
&& ist ein logisches "UND" und führt den zweiten Teil der Anweisung nur aus, wenn der erste Teil wahr ist.
Betrachten Sie diese beiden Zeilen: [ -z $1 ] && echo no argument provided
ping -c 1 8.8.8.8 2>/dev/null || echo node is not available
Im ersten Beispiel wird überprüft, ob
$ 1 leer ist. Wenn diese Prüfung korrekt ist (was im Grunde bedeutet, dass der Befehl mit dem Exit-Code 0 endet), wird der zweite Befehl ausgeführt.
Im zweiten Beispiel wird der Befehl
ping verwendet, um die Verfügbarkeit des Hosts zu überprüfen.
In diesem Beispiel wird ein logisches "ODER" verwendet, um den Text "Knoten ist nicht verfügbar" anzuzeigen, falls ein
Ping- Befehl fehlschlägt.
Sie werden das häufig anstelle der bedingten
if-Anweisung && und
|| finden . In der folgenden Übung können Sie die Verwendung von bedingten Anweisungen üben, indem Sie entweder
if ... then ... else oder
&& und
|| verwenden .
Übung . Verwenden Sie
if ... then ... elseIn dieser Übung arbeiten Sie an einem Skript, das überprüft, was eine Datei und was ein Verzeichnis ist.
- Starten Sie den Editor und erstellen Sie ein Skript namens filechk.
- Kopieren Sie den Inhalt von Listing 4 in dieses Skript.
- Führen Sie damit einige Tests durch, z. B. ./filechk / etc / hosts , ./filechck / usr , ./filechk nicht vorhandene Datei .
Für Schleife
Die
for- Schleife ist eine großartige Lösung für die Verarbeitung von Datenbereichen. In Listing 5 sehen Sie das erste Beispiel mit
for , in dem der Bereich bestimmt und verarbeitet wird, während sich Rohwerte in diesem Bereich befinden.
Listing 5:
Eine
for- Schleife beginnt immer mit dem Schlüsselwort for, gefolgt von einer Bedingung, die überprüft werden muss. Darauf folgt das Schlüsselwort
do , gefolgt von Befehlen, die ausgeführt werden müssen. Wenn die Bedingung erfüllt ist, wird die Schleife mit dem Schlüsselwort
done beendet.
Im Beispiel in Listing 5 sehen Sie, dass die Bedingung ein Zahlenbereich in Klammern ist, der der Variablen COUNTER zugewiesen ist.
Eine kleine ErklärungInnerhalb
((...)) werden arithmetische Ausdrücke berechnet und ihr Ergebnis zurückgegeben. Im einfachsten Fall weist die Konstruktion a = $ ((5 + 3)) der Variablen "a" den Wert des Ausdrucks "5 + 3" oder 8 zu. Außerdem ermöglichen doppelte Klammern das Arbeiten mit Variablen im Stil der C-Sprache.
Zuerst wird die Variable auf 100 initialisiert, und solange der Wert größer als 1 ist, wird sie bei jeder Iteration von 1 subtrahiert. Solange die Bedingung erfüllt ist, wird der Wert der Variablen $ COUNTER mit dem Befehl
echo angezeigt.
In Listing 6 sehen Sie einen meiner Lieblings-Einzeiler mit
für . Der Bereich wird diesmal als eine Folge von Zahlen definiert, die von 100 bis 104 reichen.
Listing 6: for i in {100..104}; do ping –c 1 192.168.4.$i >/dev/null && echo 192.168.4.$i is up; done
Beachten Sie, wie der Bereich bestimmt wird: Zuerst geben Sie die erste Zahl an, dann zwei Punkte und geben die letzte Zahl im Bereich an. Darüber hinaus wird mit
für i in für jede dieser Zahlen die Variable
i zugewiesen. Jede dieser Nummern wird der Variablen
i zugewiesen, und dann wird der
Ping- Befehl ausgeführt, wobei die Option
-c 1 sicherstellt, dass nur eine Anforderung gesendet wird.
Das Ergebnis des
Ping- Befehls
wird nicht berücksichtigt, daher wird seine Ausgabe nach / dev / null umgeleitet. Basierend auf dem Ausgabestatus des
Ping- Befehls wird ein Teil des Ausdrucks
&& ausgeführt. Wenn der Host verfügbar ist, wird eine Zeile angezeigt, die angibt, dass er ausgeführt wird.
Verstehen während und bis
Wenn die for-Anweisung, über die Sie gerade gelesen haben, für die Arbeit mit Elementbereichen nützlich ist, ist die while-Anweisung hilfreich, wenn Sie beispielsweise die Prozesszugänglichkeit verfolgen möchten. Es gibt auch eine
till- Anweisung, die ausgeführt wird, solange die zu prüfende Bedingung falsch ist. In Listing 7 können Sie lesen, wie
while zur Überwachung der Prozessaktivität verwendet wird.
Hinweis Ich habe nicht verstanden, was dieses Skript macht. In meinem Fall wird CentOS 7 verwendet und standardmäßig gibt es keinen Monitor, obwohl das Skript ausdrücklich sagt: Verwendung: Monitor <Prozessname>
Irgendwo für eine halbe Stunde habe ich das Monitorprogramm für CetOS gegoogelt, es aber nicht gefunden. Und im Allgemeinen ist nicht klar, welcher Seitenmonitor hier ist, wenn ps aux verwendet wird. Auf jeden Fall habe ich nicht verstanden, was dieses Skript macht. Eine große Anfrage zur Behebung dieses Problems besteht darin, den Text und / oder das Skript anzupassen.
Listing 7:
Das Skript in Listing 7 besteht aus zwei Teilen. Erstens gibt es eine
while-Schleife . Zweitens muss alles getan werden, wenn die
while-Schleife nicht mehr als wahr ausgewertet wird.
Der Kern der
while-Schleife ist der Befehl
ps mit dem Wert
$ 1 .
Beachten Sie die Verwendung von
grep -v grep , wodurch Zeilen, die den
Befehl grep enthalten, vom Ergebnis ausgeschlossen werden. Denken Sie daran, dass der Befehl
ps alle laufenden Prozesse enthält, einschließlich des
Befehls grep , an den die Ausgabe des
Befehls ps übergeben wird. Dies kann zu einer falsch positiven Übereinstimmung führen.
Die Ausgabe des Befehls
ps aux wird nach / dev / tty11 umgeleitet. Auf diese Weise können Sie die Ergebnisse von tty11 bei Bedarf später lesen, sie werden jedoch standardmäßig nicht angezeigt.
while , , .
sleep 5 , 5 .
while , . ( , ), , .
, .
mail -s “process $1 has stopped” root < . root , Linux*.
mail ,
-s .
* — CentOS . (. )< . .
mail , . , , . STDIN. - .
while —
until , 8.
until , , .
8
users $1 , . , . , ,
until .
8
case
—
case *.
case . ,
case Linux, .
* — ?case , , , .
9
case , .
9 case "$1" in start) start;; stop) rm -f $lockfile stop;; restart) restart;; reload) reload;; status) status ;; *) echo "Usage: $0 (start|stop|restart|reload|status)" ;; esac
case . —
case in . , .
) .
, , . ;; .
,
*) , . «» .
case esac .
Beachten Sie, dass die Sequenzen für den Fall der Reihe nach ausgeführt werden. Wenn die erste Übereinstimmung hergestellt wird, bewertet die case-Anweisung nichts.Im Rahmen der Bewertung können Vorlagen verwendet werden, die der Vorlage ähnlich sind. Dies wird in *) einer Sequenz gezeigt, die zu allem passt. Sie können aber auch Sequenzen wie start | Start | START verwenden, um mit einem anderen Fall übereinzustimmen .Debuggen von Skripten in Bash
, , . ,
bash -x . , , , .
10
bash -x , ,
grep , , .
[root@server1 ~]
, . , .