Website-Suche

Spezielle Bash-Variablen mit Beispielen


Bash ist eine großartige Programmiersprache, mit der Sie komplexe Dinge wie Big Data-Manipulation ausführen oder einfach Server- oder Desktop-Management-Skripte erstellen können.

Die Einstiegsfähigkeiten, die für die Verwendung der Bash-Sprache erforderlich sind, sind recht gering, und Einzeiler-Skripte (ein häufig verwendeter Jargon, der mehrere Befehle anzeigt, die auf der Befehlszeile ausgeführt werden und ein Mini-Skript bilden) sowie reguläre Skripte können an Komplexität zunehmen (und wie gut sie geschrieben sind), wenn der Bash-Entwickler mehr lernt.

Das Erlernen der Verwendung spezieller Variablen in Bash ist ein Teil dieser Lernkurve. Während die speziellen Variablen ursprünglich kryptisch aussehen mögen: $$, $?, $*, \$0, $1 usw., werden die Dinge, sobald Sie sie verstehen und in Ihren eigenen Skripten verwenden, bald klarer und leichter zu merken sein.

In diesem Tutorial lernen Sie:

  • So verwenden Sie spezielle Variablen in Bash
  • Wie man Variablen richtig zitiert, auch spezielle Variablen
  • Beispiele für die Verwendung spezieller Variablen über die Befehlszeile und Skripte

Spezielle Bash-Variablen mit Beispielen

Verwendete Softwareanforderungen und Konventionen

  1. $$– zeigt die PID (Process Identifier) an

    In diesem Beispiel verwenden wir die spezielle Variable $$, um die PID (Process Identifier) für unser aktuelles Programm anzuzeigen. Dies funktioniert etwas anders, je nachdem, ob Sie diese Variable von der Befehlszeile aus verwenden:

    echo $$
    316204
    ps -ef | grep -E "$$|PID"
    UID          PID    PPID  C STIME TTY          TIME CMD
    roel      316204   62582  0 11:53 pts/2    00:00:00 bash
    roel      316499  316204  0 11:57 pts/2    00:00:00 ps -ef
    roel      316500  316204  0 11:57 pts/2    00:00:00 grep -E 316204|PID
    

    Oder aus einem Skript heraus. Betrachten wir zum Beispiel das folgende Skript test.sh:

    echo $$
    ps -ef | grep -E "$$|PID"
    

    Was, wenn wir es ausführbar machen (chmod +x test.sh) und ausführen, Folgendes erzeugt:

    chmod +x test.sh 
    ./test.sh 
    316820
    UID          PID    PPID  C STIME TTY          TIME CMD
    roel      316820  316204  0 12:01 pts/2    00:00:00 bash
    roel      316821  316820  0 12:01 pts/2    00:00:00 ps -ef
    roel      316822  316820  0 12:01 pts/2    00:00:00 grep -E 316820|PID
    

    Der Unterschied liegt in der erzeugten PID! Das mag auf den ersten Blick konzeptionell sinnvoll sein, aber lassen Sie uns den Hauptgrund erklären, warum sich die PID unterscheidet: Wir verwenden eine andere Bash-Shell. Der erste ausgeführte Befehl erfolgte direkt auf der Kommandozeile, und daher erzeugt unsere spezielle Variable $$ (die die PID des aktuell laufenden Programms identifiziert) die PID der aktuell laufenden Bash-Shell (die 316204 ist).

    In der zweiten Instanz führen wir ein Skript aus und jeder Start eines Skripts startet immer eine neue Bash-Shell. Das Ergebnis ist, dass unsere PID die PID der neu gestarteten Bash-Shell (316820) ist. Wir können dies auch bestätigen, indem wir uns die PPID (d.h. die übergeordnete PID oder das übergeordnete Element der Prozesskennung) ansehen – es ist 316204, die mit unserer Bash-Shell übereinstimmt, von der aus wir das Skript gestartet haben, wie im ersten Beispiel zu sehen (sowohl das erste als auch das zweite Beispiel wurden im selben Terminal auf demselben Rechner ausgeführt).

    Der Befehl grep -E in unseren beiden Beispielen ermöglicht es uns, die erste Zeile der vollständigen Prozessliste der Maschine (wie von ps -ef erhalten) zu erfassen, indem wir neben unserer PID (mit $$) erweiterte Regex-Unterstützung und Grepping für PID zulassen. Das | ist das erweiterte Trennzeichen für reguläre Ausdrücke, das diese duale Erfassung ermöglicht.

    Weitere Informationen zu regulären Ausdrücken finden Sie in unseren Artikeln Bash-Regexps für Anfänger mit Beispielen und Fortgeschrittene Bash-Regex mit Beispielen.

    Beachten Sie auch, dass wir die PID-Erfassung automatisiert haben, indem wir $$ im grep-Befehl verwendet haben. Diese $$-Variable ändert sich nie, es sei denn, es wird eine neue Bash-Shell/Sub-Shell gestartet, wie wir im folgenden Beispiel sehen können:

    echo $$
    316204
    bash
    echo $$
    318023
    echo $PPID
    316204
    

    Die PID unserer Bash-Hauptshell ist immer noch 316204 wie zuvor. Als nächstes starten wir eine neue Unterschale und die PID dieser neuen Schale wird bei der Überprüfung 318023. Und mit der automatisch gesetzten (von Bash) Variablen $PPID können wir die PPID (Parent Process ID) der sekundären Bash-Shell/Sub-Shell als 316204 bestätigen, die mit unserer Haupt-Shell übereinstimmt. Wie Sie sehen können, gibt es in Bezug auf das Prozessmanagement und speziell die Variable $$ keinen großen Unterschied zwischen dem Starten eines Skripts und einer neuen Subshell.

    Weitere Informationen zum Bash-Prozessmanagement finden Sie in unseren Artikeln Bash-Hintergrundprozessmanagement und Prozesslistenverwaltung und Automatische Prozessbeendigung.

  2. $? – Exit-Code

    Die Variable $? teilt uns mit, wie der Exit-Code des vorherigen Befehls lautete. Wenn wir den Exit-Code einer ausgeführten Anweisung kennen, können wir ein Skript in zwei oder mehr verschiedene Richtungen fortsetzen. Wenn wir beispielsweise einen rm-Befehl (zum Löschen einiger Dateien) aus einem Programm heraus gestartet haben, möchten wir möglicherweise überprüfen, ob der Vorgang erfolgreich abgeschlossen wurde.

    Wenn der Exit-Code 0 ist, bedeutet dies in der Regel (sprich: fast immer), dass ein Prozess erfolgreich beendet wurde. Wenn der Exit-Code jedoch 1 (oder mehrere) ist, bedeutet dies oft (wenn auch nicht immer), dass der Prozess mit einem Fehler oder negativem Ergebnis beendet wurde, z. B. konnte die Datei in unserem Beispiel nicht gelöscht werden. Schauen wir uns an, wie dies auf der Befehlszeile funktioniert, wobei wir uns daran erinnern, dass die Funktionsweise dieser Variablen innerhalb eines Skripts identisch ist.

    touch this.exists
    rm this.exists
    echo $?
    0
    rm this.does.not.exist
    rm: cannot remove 'this.does.not.exist': No such file or directory
    echo $?
    1
    

    Wir erstellen zuerst eine Datei this.exists mit dem Touch-Befehl. Touch erstellt einfach eine Datei mit der Größe Null, ohne etwas in sie zu schreiben. Als nächstes entfernen wir die Datei mit rm this.exists und zeigen den $? Exit-Code mit echo an. Das Ergebnis ist 0, da der Befehl wie erwartet erfolgreich war und kein Fehler zurückgegeben wird.

    Als nächstes versuchen wir, eine Datei zu löschen, die nicht existiert, und erhalten eine Fehlermeldung. Wenn wir den Exit-Code überprüfen, ist er tatsächlich 1, was darauf hinweist, dass ein Fehler aufgetreten ist. Wir können den Wert dieser Variablen leicht über die Befehlszeile oder innerhalb eines Skripts überprüfen, indem wir eine if [ $? -eq 0 ]; then oder eine ähnliche bedingte Anweisung (beendet durch fi) verwenden.

  3. Um mehr über if-basierte Anweisungen zu erfahren, lesen Sie bitte Bash If-Anweisungen If Elif Else Then Fi. Das Kombinieren von $? mit if-Anweisungen ist eine gängige und leistungsstarke Methode, um verschiedene Dinge in Bash zu automatisieren.

  4. 1 $, 2 $, ... $* – Argumente übergeben

    Wenn wir ein Skript an der Bash-Befehlszeile starten, können wir Argumente an dasselbe übergeben. Es liegt ganz im Ermessen des Skripts, die an das Skript übergebenen Argumente zu verarbeiten. Wenn das Skript z. B. überhaupt keine Argumente verarbeitet (die Standardeinstellung), hat es keine Konsequenzen, wenn Sie in einem Skript eine oder mehrere Variablen angeben oder nicht angeben.

    Wir können mit übergebenen Argumenten umgehen, indem wir die speziellen Variablen $1, $2, $* usw. verwenden. Das erste Argument, das an das Skript übergeben wird, ist immer $1, das zweite Argument ist immer $2 usw. Eine Sache, auf die Sie achten sollten, ist, dass, wenn Sie ein Leerzeichen in einem standardmäßig konfigurierten Bash-Client einführen, Bash dieses Leerzeichen als Trennzeichen interpretiert.

    Wenn Sie versuchen, einen Text zu übergeben, wie zum Beispiel, dies ist ein Beispiel, müssten Sie ihn richtig zitieren, wie folgt: "Dies ist ein Beispiel"; damit Bash diesen Text als eine einzelne Variable sieht, die übergeben wird.

    Die spezielle Variable $* ist eine Abkürzung für das Schreiben aller Variablen in einen einzigen String. Sehen wir uns an, wie dies funktioniert, indem wir ein neues test2.sh-Skript wie folgt definieren:

    echo "1: ${1}"
    echo "2: ${2}"
    echo "All: ${*}"
    

    Als kleine Variation haben wir uns dafür entschieden, unsere Variablen hier als $ {1} bis $ {*} anstelle von $1 bis $* zu definieren. In der Tat wäre es eine gute Idee, Variablen immer auf diese Weise zu zitieren. Weitere Informationen finden Sie in unserem Artikel Korrektes Variablen-Parsing und Zitating in Bash.

    Wenn wir dasselbe mit zwei oder drei Argumenten ausführen, sehen wir:

    chmod +x test2.sh 
    ./test2.sh '1' '2'
    1: 1
    2: 2
    All: 1 2
    ./test2.sh '1' '2' '3'
    1: 1
    2: 2
    All: 1 2 3
    

    Wir können sehen, wie unsere erste Eingabe in das Skript korrekt als $1 usw. erkannt wird. Außerdem stellen wir fest, dass das dritte Argument vom Skript vollständig ignoriert wird, bis es die Echo-Anweisung "All: $ {*}" erreicht, die tatsächlich alle Argumente anzeigt, wie zuvor besprochen. Schauen wir uns nun eine falsche Eingabe ohne Zitat an:

    ./test2.sh This is meant to be a single sentence.
    1: This
    2: is
    All: This is meant to be a single sentence.
    ./test2.sh "This is meant to be a single sentence."
    1: This is meant to be a single sentence.
    2: 
    All: This is meant to be a single sentence.
    

    Hier wird deutlich, wie ein Leerzeichen als Trennzeichen statt als tatsächliches Leerzeichen interpretiert werden kann, es sei denn, der Text wird richtig zitiert. Im ersten Ergebnis wird Dies als erstes Argument angesehen, während im zweiten Ergebnis der gesamte Satz als erstes Argument angesehen wird.

  5. $0 – der Befehl, der ausgeführt

    wird

    Nachdem man etwas über $1 gelernt hat, könnte man sich fragen, was die spezielle Variable \$0 macht. Wenn Sie darüber nachdenken, wie ein Befehl gebildet wird (Befehl, Argument1, Argument2 usw.), bemerken Sie vielleicht, dass der Befehl vor dem ersten Argument ($1) steht. Command ist also in gewisser Weise – visuell – \$0, und das ist genau das, was die spezielle Variable \$0 enthält; Der Befehl wird ausgeführt.

    echo \$0
    bash
    

    Wie wir sehen können und wie es sinnvoll ist, ist der aktuell ausgeführte Befehl auf der Befehlszeile bash. Wenn wir den Befehl echo \$0 zu einem Testskript hinzufügen test3.sh und ausführen, erhalten wir:

    ./test3.sh 
    ./test3.sh
    ../workspace/test3.sh 
    ../workspace/test3.sh
    
  6. Wie bisher ist der aktuell laufende Befehl ./test3.sh, genau so, wie er von der Kommandozeile ausgeführt wird. Wenn wir den Befehl mit einem längeren Pfadnamen wie .. /workspace/test3.sh dann wieder wird dies über die spezielle Variable \$0 wiederholt.

Schlussfolgerung

In diesem Artikel haben wir die Variablen $$, $?, $1, $2 usw., $* und \$0 untersucht, wie sie funktionieren und wie Sie sie entweder direkt von der Befehlszeile oder aus Skripten heraus verwenden können. Es gibt noch ein paar andere spezielle Variablen, aber dies sind die wichtigsten speziellen Variablen in Bash, die ich in vielen Jahren der Bash-Codierung verwendet habe. Genießen!

Verwandte Artikel: