So verwenden Sie getopts zum Analysieren von Linux-Shell-Skriptoptionen

Veröffentlicht: 2022-06-25
Ein Laptop-Bildschirm mit Terminaltext.
fatmawati achmad zaenuri/Shutterstock.com

Möchten Sie, dass Ihre Linux-Shell-Skripts Befehlszeilenoptionen und -argumente eleganter handhaben? Mit dem integrierten Bash getopts können Sie Befehlszeilenoptionen mit Finesse parsen – und es ist auch einfach. Wir zeigen Ihnen wie.

Einführung in die eingebauten Getopts

Das Übergeben von Werten an ein Bash-Skript ist ziemlich einfach. Sie rufen Ihr Skript von der Befehlszeile oder von einem anderen Skript aus auf und geben Ihre Werteliste hinter dem Skriptnamen an. Auf diese Werte kann in Ihrem Skript als Variablen zugegriffen werden, beginnend mit $1 für die erste Variable, $2 für die zweite und so weiter.

Will man aber Optionen an ein Skript übergeben, wird die Situation schnell komplexer. Wenn wir Optionen sagen, meinen wir die Optionen, Flags oder Schalter, die Programme wie ls verarbeiten können. Ihnen ist ein Bindestrich „ - “ vorangestellt und dient normalerweise als Indikator für das Programm, um einen Aspekt seiner Funktionalität ein- oder auszuschalten.

So verwenden Sie den Befehl ls zum Auflisten von Dateien und Verzeichnissen unter Linux
VERWANDTE Verwendung des Befehls ls zum Auflisten von Dateien und Verzeichnissen unter Linux

Der Befehl ls hat über 50 Optionen, die sich hauptsächlich auf die Formatierung seiner Ausgabe beziehen. Die Option -X (nach Erweiterung sortieren) sortiert die Ausgabe alphabetisch nach Dateierweiterung. Die Option -U (unsortiert) listet nach Verzeichnisreihenfolge auf.

Optionen sind genau das – sie sind optional. Sie wissen nicht, welche Optionen der Benutzer gegebenenfalls verwenden wird, und Sie wissen auch nicht, in welcher Reihenfolge er sie auf der Befehlszeile auflisten wird. Dies erhöht die Komplexität des Codes, der zum Analysieren der Optionen erforderlich ist.

Die Dinge werden noch komplizierter, wenn einige Ihrer Optionen ein Argument annehmen, das als Optionsargument bekannt ist. Beispielsweise erwartet die Option ls -w (Breite) eine Zahl gefolgt von einer Zahl, die die maximale Anzeigebreite der Ausgabe darstellt. Und natürlich könnten Sie andere Parameter an Ihr Skript übergeben, die einfach Datenwerte sind, die überhaupt keine Optionen sind.

Glücklicherweise handhabt getopts diese Komplexität für Sie. Und da es sich um eine integrierte Funktion handelt, ist sie auf allen Systemen verfügbar, die über die Bash-Shell verfügen, sodass nichts installiert werden muss.

Hinweis: getopts Nicht getopt

Es gibt ein älteres Dienstprogramm namens getopt . Dies ist ein kleines Hilfsprogramm , kein eingebautes. Es gibt viele verschiedene Versionen von getopt mit unterschiedlichem Verhalten, während das getops den POSIX-Richtlinien folgt.

 gib getopts ein
 gib getopt ein 

Verwenden Sie den Befehl type, um den Unterschied zwischen getop und getops zu sehen

Da getopt kein eingebautes Programm ist, bietet es einige der automatischen Vorteile von getopts nicht, wie z. B. den vernünftigen Umgang mit Leerzeichen. Mit getopts führt die Bash-Shell Ihr Skript aus und die Bash-Shell führt die Optionsanalyse durch. Sie müssen kein externes Programm aufrufen, um die Analyse durchzuführen.

Der Kompromiss besteht darin, dass getopts keine doppelt gestrichelten Optionsnamen im Langformat verarbeitet. Sie können also Optionen verwenden, die wie -w formatiert sind, aber nicht " ---wide-format ". Wenn Sie andererseits ein Skript haben, das die Optionen -a , -b und -c getopts , können Sie sie mit getopts wie -abc , -bca oder -bac usw. kombinieren.

Wir diskutieren und demonstrieren in diesem Artikel getopts , stellen Sie also sicher, dass Sie dem Befehlsnamen das abschließende „s“ hinzufügen.

VERWANDT: Wie man Leerzeichen in Dateipfaden auf der Windows-Befehlszeile maskiert

Eine kurze Zusammenfassung: Umgang mit Parameterwerten

Dieses Skript verwendet keine gestrichelten Optionen wie -a oder -b . Es akzeptiert „normale“ Parameter in der Befehlszeile und auf diese wird im Skript als Werte zugegriffen.

 #!/bin/bash

# Die Variablen einzeln abrufen
echo "Variable Eins: $1" 
echo "Variable Zwei: $2" 
echo "Variable Drei: $3"

# Schleife durch die Variablen
für var in " $@" tun
echo "$ var" 
erledigt

Auf die Parameter wird innerhalb des Skripts als Variablen $1 , $2 oder $3 zugegriffen.

Kopieren Sie diesen Text in einen Editor und speichern Sie ihn als Datei namens „variables.sh“. Wir müssen es mit dem Befehl chmod ausführbar machen. Sie müssen diesen Schritt für alle Skripte ausführen, die wir besprechen. Ersetzen Sie einfach jedes Mal den Namen der entsprechenden Skriptdatei.

 chmod +x Variablen.sh 

Verwenden Sie den Befehl chmod, um ein Skript ausführbar zu machen

Wenn wir unser Skript ohne Parameter ausführen, erhalten wir diese Ausgabe.

 ./variables.sh 

Ausführen eines Skripts ohne Parameter

Wir haben keine Parameter übergeben, sodass das Skript keine Werte zu melden hat. Geben wir diesmal einige Parameter an.

 ./variables.sh wie man geekt 

Ausführen eines Skripts mit drei Wörtern als Parameter

Wie erwartet wurden die Variablen $1 , $2 und $3 auf die Parameterwerte gesetzt und wir sehen diese gedruckt.

Diese Art der Eins-zu-Eins-Parameterbehandlung bedeutet, dass wir im Voraus wissen müssen, wie viele Parameter es geben wird. Die Schleife am Ende des Skripts kümmert sich nicht darum, wie viele Parameter es gibt, sie durchläuft sie immer alle.

Wenn wir einen vierten Parameter angeben, wird dieser keiner Variablen zugewiesen, aber die Schleife behandelt ihn trotzdem.

 ./variables.sh How-to-Geek-Website 

Übergeben von vier Parametern an ein Skript, das nur drei verarbeiten kann

Wenn wir zwei der Wörter in Anführungszeichen setzen, werden sie als ein Parameter behandelt.

 ./variables.sh wie "Geek" 

zwei Befehlszeilenparameter in Anführungszeichen setzen, damit sie als ein Parameter behandelt werden

Wenn unser Skript alle Kombinationen von Optionen, Optionen mit Argumenten und „normalen“ Datentypparametern handhaben soll, müssen wir die Optionen von den regulären Parametern trennen. Das erreichen wir, indem wir alle Optionen – mit oder ohne Argumente – vor die regulären Parameter stellen.

Aber lass uns nicht laufen, bevor wir laufen können. Schauen wir uns den einfachsten Fall für die Handhabung von Befehlszeilenoptionen an.

Handhabungsoptionen

Wir verwenden getopts in einer while -Schleife. Jede Iteration der Schleife arbeitet mit einer Option, die an das Skript übergeben wurde. In jedem Fall wird die Variable OPTION auf die durch getopts identifizierte Option gesetzt.

Mit jeder Iteration der Schleife geht getopts zur nächsten Option über. Wenn es keine weiteren Optionen gibt, gibt getopts false zurück und die while -Schleife wird beendet.

So verwenden Sie Case-Anweisungen in Bash-Skripten
VERWANDTE Verwendung von Case-Anweisungen in Bash-Skripten

Die OPTION Variable wird mit den Mustern in jeder der case-Anweisungsklauseln abgeglichen. Da wir eine case-Anweisung verwenden, spielt es keine Rolle, in welcher Reihenfolge die Optionen auf der Befehlszeile bereitgestellt werden. Jede Option wird in die case-Anweisung eingefügt und die entsprechende Klausel wird ausgelöst.

Die einzelnen Klauseln in der case-Anweisung machen es einfach, optionsspezifische Aktionen innerhalb des Skripts auszuführen. In einem realen Skript würden Sie normalerweise in jeder Klausel eine Variable setzen, die später im Skript als Flags fungieren und einige Funktionen zulassen oder verweigern würden.

Kopieren Sie diesen Text in einen Editor und speichern Sie ihn als Skript mit dem Namen „options.sh“ und machen Sie ihn ausführbar.

 #!/bin/bash

while getopts 'abc' OPTION; tun
  Fall "$OPTION" in 
    a) 
      echo "Option a verwendet" ;;

    b)
      echo "Option b verwendet"
      ;;

    c)
      echo "Option c verwendet"
      ;;

    ?) 
      echo "Verwendung: $(Basisname $0) [-a] [-b] [-c]"
      Ausgang 1
      ;;
  esac
erledigt

Dies ist die Zeile, die die While-Schleife definiert.

 while getopts 'abc' OPTION; tun

Auf den getopts Befehl folgt die Optionszeichenfolge . Dies listet die Buchstaben auf, die wir als Optionen verwenden werden. Nur Buchstaben in dieser Liste können als Optionen verwendet werden. In diesem Fall wäre -d also ungültig. Dies würde durch die ?) Klausel abgefangen, da getopts ein Fragezeichen „ ? “ für eine nicht identifizierte Option. In diesem Fall wird die korrekte Verwendung im Terminalfenster ausgegeben:

 echo "Verwendung: $(Basisname $0) [-a] [-b] [-c]"

Per Konvention bedeutet das Einschließen einer Option in eckige Klammern „ [] “ in dieser Art von Meldung zur korrekten Verwendung, dass die Option optional ist. Der basename-Befehl entfernt alle Verzeichnispfade aus dem Dateinamen. Der Name der Skriptdatei wird in Bash-Skripten in $0 gespeichert.

Lassen Sie uns dieses Skript mit verschiedenen Befehlszeilenkombinationen verwenden.

 ./options.sh -a
 ./options.sh -a -b -c
 ./options.sh -ab -c
 ./options.sh -cab 

Testen eines Skripts, das Befehlszeilenoptionen vom Typ switch akzeptieren kann

Wie wir sehen können, werden alle unsere Testkombinationen von Optionen korrekt geparst und behandelt. Was ist, wenn wir eine Option ausprobieren, die es nicht gibt?

 ./options.sh -d 

Eine nicht erkannte Option, die von der Shell und dem Skript gemeldet wird

Die Verwendungsklausel wird ausgelöst, was gut ist, aber wir erhalten auch eine Fehlermeldung von der Shell. Das kann für Ihren Anwendungsfall von Bedeutung sein oder auch nicht. Wenn Sie das Skript von einem anderen Skript aus aufrufen, das Fehlermeldungen analysieren muss, wird es schwieriger, wenn die Shell auch Fehlermeldungen generiert.

Das Ausschalten der Shell-Fehlermeldungen ist sehr einfach. Alles, was wir tun müssen, ist einen Doppelpunkt ” : ” als erstes Zeichen der Optionszeichenfolge zu setzen.

Bearbeiten Sie entweder Ihre Datei „options.sh“ und fügen Sie einen Doppelpunkt als erstes Zeichen der Optionszeichenfolge hinzu, oder speichern Sie dieses Skript als „options2.sh“ und machen Sie es ausführbar.

 #!/bin/bash

while getopts ':abc' OPTION; tun
  Fall "$OPTION" in 
    a) 
      Echo "Option a verwendet" 
      ;;

    b)
      echo "Option b verwendet"
      ;;

    c)
      echo "Option c verwendet"
      ;;

    ?) 
      echo "Verwendung: $(Basisname $0) [-a] [-b] [-c]"
      Ausgang 1
      ;;
  esac
erledigt

Wenn wir dies ausführen und einen Fehler generieren, erhalten wir unsere eigenen Fehlermeldungen ohne Shell-Nachrichten.

 ./options2.sh.sh -d 

Eine nicht erkannte Option, die nur vom Skript gemeldet wird

Verwenden von getopts mit Optionsargumenten

Um getopts mitzuteilen, dass auf eine Option ein Argument folgt, setzen Sie einen Doppelpunkt ” : ” direkt hinter den Optionsbuchstaben in der Optionszeichenfolge.

Wenn wir dem „b“ und „c“ in unserem Optionsstring Doppelpunkte folgen lassen, erwartet getopt Argumente für diese Optionen. Kopieren Sie dieses Skript in Ihren Editor und speichern Sie es als „arguments.sh“ und machen Sie es ausführbar.

Denken Sie daran, dass der erste Doppelpunkt in der Optionszeichenfolge verwendet wird, um Shell-Fehlermeldungen zu unterdrücken – er hat nichts mit der Verarbeitung von Argumenten zu tun.

Wenn getopt eine Option mit einem Argument verarbeitet, wird das Argument in die Variable OPTARG gestellt. Wenn Sie diesen Wert an anderer Stelle in Ihrem Skript verwenden möchten, müssen Sie ihn in eine andere Variable kopieren.

 #!/bin/bash

while getopts ':ab:c:' OPTION; tun

  Fall "$OPTION" in
    a)
      Echo "Option a verwendet"
      ;;

    b)
      argB="$OPTARG"
      echo "Option b verwendet mit: $argB"
      ;;

    c)
      argC="$OPTARG"
      echo "Option c verwendet mit: $argC"
      ;;

    ?)
      echo "Verwendung: $(Basisname $0) [-a] [-b Argument] [-c Argument]"
      Ausgang 1
      ;;
  esac

erledigt

Lassen Sie uns das ausführen und sehen, wie es funktioniert.

 ./arguments.sh -a -b "how to geek" -c reviewgeek
 ./arguments.sh -c reviewgeek -a 

Testen eines Skripts, das Optionsargumente verarbeiten kann

Jetzt können wir also Optionen mit oder ohne Argumente handhaben, unabhängig von der Reihenfolge, in der sie auf der Befehlszeile angegeben werden.

Aber was ist mit regulären Parametern? Wir sagten vorhin, dass wir wussten, dass wir diese nach allen Optionen in die Befehlszeile einfügen müssten. Mal sehen, was passiert, wenn wir das tun.

Mischoptionen und Parameter

Wir ändern unser vorheriges Skript so, dass es eine weitere Zeile enthält. Wenn die while -Schleife beendet ist und alle Optionen behandelt wurden, versuchen wir, auf die regulären Parameter zuzugreifen. Wir geben den Wert in $1 aus.

Speichern Sie dieses Skript als „arguments2.sh“ und machen Sie es ausführbar.

 #!/bin/bash

while getopts ':ab:c:' OPTION; tun

  Fall "$OPTION" in
    a)
      Echo "Option a verwendet"
      ;;

    b)
      argB="$OPTARG"
      echo "Option b verwendet mit: $argB"
      ;;

    c)
      argC="$OPTARG"
      echo "Option c verwendet mit: $argC"
      ;;

    ?)
      echo "Verwendung: $(Basisname $0) [-a] [-b Argument] [-c Argument]"
      Ausgang 1
      ;;
  esac

erledigt

echo "Variable eins ist: $1"

Jetzt werden wir ein paar Kombinationen von Optionen und Parametern ausprobieren.

 ./arguments2.sh Dave
 ./arguments2.sh -ein dave
 ./arguments2.sh -a -c how-to-geek dave 

Fehler beim Zugriff auf Standardparameter in einem Skript, das Optionsargumente akzeptiert

So, jetzt können wir das Problem sehen. Sobald Optionen verwendet werden, werden die Variablen ab $1 mit den Optionsflags und deren Argumenten gefüllt. Im letzten Beispiel würde $4 den Parameterwert „dave“ enthalten, aber wie greifen Sie in Ihrem Skript darauf zu, wenn Sie nicht wissen, wie viele Optionen und Argumente verwendet werden?

Die Antwort ist die Verwendung von OPTIND und dem shift Befehl.

Der shift -Befehl verwirft den ersten Parameter – egal welchen Typs – aus der Parameterliste. Die anderen Parameter „mischen nach unten“, sodass Parameter 2 zu Parameter 1 wird, Parameter 3 zu Parameter 2 und so weiter. Und so wird aus $2 $1 , aus $3 wird $2 und so weiter.

Wenn Sie shift mit einer Zahl versehen, werden so viele Parameter aus der Liste entfernt.

OPTIND zählt die Optionen und Argumente, sobald sie gefunden und verarbeitet werden. Sobald alle Optionen und Argumente verarbeitet wurden, ist OPTIND um eins höher als die Anzahl der Optionen. Wenn wir also Shift verwenden, um (OPTIND-1) Parameter aus der Parameterliste zu entfernen, bleiben die regulären Parameter ab $1 übrig.

Genau das macht dieses Skript. Speichern Sie dieses Skript als „arguments3.sh“ und machen Sie es ausführbar.

 #!/bin/bash

while getopts ':ab:c:' OPTION; tun
  Fall "$OPTION" in
    a)
      Echo "Option a verwendet"
      ;;

    b)
      argB="$OPTARG"
      echo "Option b verwendet mit: $argB"
      ;;

    c)
      argC="$OPTARG"
      echo "Option c verwendet mit: $argC"
      ;;

    ?)
      echo "Verwendung: $(Basisname $0) [-a] [-b Argument] [-c Argument]"
      Ausgang 1
      ;;
  esac
erledigt

echo "Vorher - Variable eins ist: $1"
Verschiebung "$(($OPTIND -1))"
echo "Danach - Variable eins ist: $1"
echo "Die restlichen Argumente (Operanden)"

für x in "$@"
tun
  echo $x
erledigt

Wir führen dies mit einer Mischung aus Optionen, Argumenten und Parametern aus.

 ./arguments3.sh -a -c how-to-geek "dave dee" dozy beaky mick tich 

Korrekter Zugriff auf Standardparameter in einem Skript, das Optionsargumente akzeptiert

Wir können sehen, dass $1 vor dem Aufruf von shift „-a“ enthielt, aber nach dem Shift-Befehl enthält $1 unseren ersten Nicht-Options-, Nicht-Argument-Parameter. Wir können alle Parameter genauso einfach durchlaufen wie in einem Skript ohne Optionsparsing.

Es ist immer gut, Optionen zu haben

Der Umgang mit Optionen und ihren Argumenten in Skripten muss nicht kompliziert sein. Mit getopts können Sie Skripte erstellen, die Befehlszeilenoptionen, Argumente und Parameter genau so verarbeiten, wie es POSIX-konforme native Skripte tun sollten.