Übergeben von Argumenten an ein Skript

Übergeben von Argumenten an ein Skript

Ich besuche den Kurs „Linux Essentials“ und kam gut voran, bis ich zum Kapitel „Scripting“ kam. Ich verstehe diese Konzepte einfach nicht. Ich frage mich, ob jemand das Folgende in extrem einfache Begriffe aufschlüsseln oder mir eine bessere Referenz zum Erlernen nennen kann. Ich verwende derzeit den Lehrplan von Netacad.


Aus dem Lehrbuch (mit geringfügigen Formatierungsänderungen):

Zusätzlich zu den von Ihnen festgelegten Variablen gibt es einige spezielle Variablen. Sie können Argumente an Ihr Skript übergeben:

#!/bin/bash
echo "Hello $1"

Ein Dollarzeichen gefolgt von einer Zahl N entspricht dem N-ten Argument, das an das Skript übergeben wird. Wenn Sie das obige Beispiel aufrufen, ./test.shlautet die Ausgabe Hello Linux. Die $0Variable enthält den Namen des Skripts selbst.

Nach der Ausführung eines Programms (egal ob es sich um eine Binärdatei oder ein Skript handelt) wird ein Exit-Code zurückgegeben, der eine Ganzzahl zwischen 0 und 255 ist. Sie können dies anhand der $?Variablen testen, um zu sehen, ob der vorherige Befehl erfolgreich ausgeführt wurde.


Ich verstehe, wie man Variablen zuweist und wie sie damit funktionieren, $aber die ganze Sache mit $0und $1– ich verstehe es einfach nicht.

Ich wäre für jede Hilfe sehr dankbar.

Antwort1

Die Beschreibung im Buch ist falsch (oder es fehlt zumindest etwas). Um das Skript dazu zu bringen, „Hallo Linux“ auszugeben, führen Sie es wie folgt aus:

./test.sh Linux

Wenn Sie es nur mit ausführen ./test.sh, wird nur „Hello “ ausgegeben, da kein erstes Argument vorhanden war und $1es nicht definiert ist. Nehmen wir andererseits an, Sie haben es folgendermaßen ausgeführt:

./test.sh foo bar baz

$0dann wäre innerhalb des Skripts „./test.sh“, $1wäre „foo“, $2wäre „bar“ und $3wäre „baz“.

Beachten Sie hierzu $?den folgenden Skriptausschnitt:

ls nonexistentfile.txt
echo "The exit status of ls was: $?"
echo "The exit status of echo (the first one) was: $?"

Beim Ausführen wird etwa Folgendes ausgegeben:

ls: nonexistentfile.txt: No such file or directory
The exit status of ls was: 1
The exit status of echo (the first one) was: 0

Der lsBefehl kann nonexistentfile.txt nicht auflisten (weil es nicht existiert), also gibt er eine entsprechende Fehlermeldung aus und beendet sich mit einem Status ungleich Null, um anzuzeigen, dass etwas schiefgelaufen ist. Der erste echoBefehl gibt diesen Beendigungsstatus ( $?) aus, und da er dies erfolgreich tut, wird er mit einem Status von Null beendet. Wenn der zweite echoBefehl ausgeführt wird, erhält er den Status $?vom ersten echoBefehl und gibt daher „0“ aus.

Übrigens verwenden viele Befehle nur Exit-Status von 0 (Erfolg) oder 1 (irgendeine Art von Fehler), aber einige verwenden unterschiedliche Fehlerstatus, um genau anzugeben, was schief gelaufen ist. Hier ist ein Auszug aus demcurlHandbuchseite:

EXIT CODES
       There are a bunch of different  error  codes  and  their  corresponding
       error  messages  that  may appear during bad conditions. At the time of
       this writing, the exit codes are:

       1      Unsupported protocol. This build of curl has no support for this
              protocol.

       2      Failed to initialize.

       3      URL malformed. The syntax was not correct.

       ...

       88     FTP chunk callback reported error

       89     No connection available, the session will be queued

       90     SSL public key does not matched pinned public key

       91     Invalid SSL certificate status.

       92     Stream error in HTTP/2 framing layer.

...damit ein verwendetes Skript curlherausfinden kann $?, was schiefgelaufen ist, und je nach Problem unterschiedlich reagieren kann.

Antwort2

$0ist der Name, den Sie zum Ausführen des Skripts verwenden. $1, $2, usw. sind die Positionsparameter des Skripts, die die Werte der Befehlszeilenargumente enthalten, die Sie beim Ausführen des Skripts übergeben haben.

AlsGordon Davisson sagte, muss der Autor des Buches gemeint haben, dass beim Ausführen ./test Linuxausgegeben wird Hello Linux. Wenn Sie das tun, ./testgeht in den speziellen Parameter 0und Linuxin den ersten Positionsparameter 1. Das Skript erweitert diesen ersten Positionsparameter, indem es ihm ein Dollarzeichen ( $1) voranstellt, genau wie Sie es mit Variablen tun. Wenn Sie stattdessen ausgeführt hätten ./test Hello Linux for Human Beings, würde im Skript zu , zu , zu und zu $1erweitert .Linux$2for$3Human$4Beings

Sie können ein einfaches Skript schreiben, um dies auszuprobieren:

#!/bin/bash

echo "\$0 expands to '$0'."
echo "\$1 expands to '$1'."
echo "\$2 expands to '$2'."
echo "\$3 expands to '$3'."

(Machen Sie so weit weiter, wie Sie wollen. Für Positionsparameter, die höher sind als 9, verwenden Sie die ${ }Form der Parametererweiterung, z. B. erweitern Sie, 10indem Sie schreiben ${10}. In Skripten, die mit vielen Positionsparametern arbeiten, @wird häufig der spezielle Parameter verwendet, um Wiederholungen zu vermeiden, aber Sie können das vorerst ignorieren, wenn Sie möchten.)

Versuchen Sie, das in einer Datei zu speichern und die Datei als ausführbar zu markieren. Dies können Sie tun, indem Sie ausführen, chmod +x simplewobei durch den Namen der Datei ersetzt wird, falls dieser abweicht. Anschließend können Sie es mit Befehlen wie , , , usw. simpleausführen ../simple./simple foo./simple foo bar

Sie werden feststellen, dass Positionsparameter, die den nicht übergebenen entsprechen, zu einer leeren Zeichenfolge erweitert werden, wenn weniger als drei Befehlszeilenargumente übergeben werden. Das passiert, wenn Sie versuchen, einen Shell-Parameter zu erweitern, der nicht definiert ist. Sie werden außerdem feststellen, dass bei der Übergabe mehrerer Befehlszeilenargumente die nach dem dritten nicht verwendet werden. Das ist wahrscheinlich das, was Sie erwarten würden, da das Skript überhaupt nicht auf sie verweist.

Versuchen Sie nun, auszuführen ./simple *. Die Shell erweitert *alle Dateinamen im aktuellen Verzeichnis außer denen, die mit beginnen .. Daher werden drei davon als die ersten drei Positionsparameter angezeigt (oder weniger, wenn es nicht so viele sind). Sie können versuchen, es mit anderen Shell-Erweiterungen auszuführen, beispielsweise ./simple {5..10}.

Sie können Befehlszeilenargumente mit Leerzeichen übergeben, indem Sie sie in Anführungszeichen setzen. Versuchen Sie es beispielsweise mit ./simple 'foo bar' baz. Beachten Sie, dass sich dies $1auf foo bardieses Mal erweitert und nicht nur auf foo.

Denn die Schale leistetdiverse Erweiterungenist es nicht immer offensichtlich, wie viele Befehlszeilenargumente Sie an einen Befehl übergeben. Eine einfache Möglichkeit, um zu sehen, was jedes Argument sein wird, besteht darin, den Befehl durch zu ersetzen printf '[%s]\n'. Beispiel:

$ printf '[%s]\n' f*
[fonts]
[fstab]
[fuse.conf]
[fwupd]
$ printf '[%s]\n' {1,3}{a..c}
[1a]
[1b]
[1c]
[3a]
[3b]
[3c]

Da Sie erst vor kurzem mit Shell-Skripten begonnen haben,Bash-Referenzhandbuchkann eine Herausforderung sein, und Sie möchten es vielleicht nicht von vorne bis hinten lesen. Aber ich denke, es ist eine wertvolle Ressource, selbst wenn Sie sich als absoluter Anfänger betrachten. Vielleicht finden Sie den Abschnitt überShell-Parameternützlich, da es mit dem beginnt, was Sie bereits wissen – Shell-Variablen – und dann zu speziellen Parametern wie ?(was die Leute oft als $?Parameter bezeichnen, da Sie es so erweitern). Für allgemeines Lernen über Bash, insbesondere auf einer eher einführenden Ebene, empfehle ichdiese Seiten, einschließlichBashGuide.

Antwort3

Ein gutes Buch, das Sie kennen sollten, ist William Shotts' "The Linux Command Line", erschienen bei No Starch Press und als kostenloses PDF erhältlich auf derWebsite des Autors.

In jedem Shell-Skript gibt es eine Sammlung nummerierter Variablen, die im Allgemeinen als $1, $2, usw. bezeichnet werden. Dies sind die „Positionsparameter“, besser bekannt als Befehlszeilenargumente. Sie können sich diese als Variablen mit den Namen 1, 2, usw. vorstellen und um ihre Werte zu erhalten, verwenden Sie $1, $2, usw. Wenn Sie ein Skript mit dem Namen my_scriptüber die Befehlszeile aufrufen ./my_script a b c, erhält es drei Argumente, die in den drei Variablen $1, $2, und gespeichert sind $3. Sie können diesen Variablen keine Zuweisungen geben (außer als Gruppe), aber Sie können ihre Werte untersuchen und verwenden. Beispielsweise echo "$1"würde das erste Argument in Ihr Skript ausgegeben.

$0ist etwas ungewöhnlich; es ist der Name, unter dem das von Ihnen ausgeführte Skript aufgerufen wurde. Im obigen Fall hätte es den Wert ./my_script. Auch hier können Sie den Wert sehen, aber nicht ändern.

$?ist der „Exit-Status“ des gerade ausgeführten Befehls. Wenn der Befehl erfolgreich war, lautet sein Exit-Status 0und andernfalls ist es eine kleine positive Ganzzahl. Sie können $?mit Null vergleichen, um zu sehen, ob der vorherige Befehl erfolgreich war oder fehlgeschlagen ist. Beispielsweise führen die folgenden beiden Befehlszeilen den grepBefehl aus und geben dann ein Echo aus, <1>weil der grepBefehl fehlgeschlagen ist und mit dem Status 1(was anzeigt, dass er fehlgeschlagen ist) beendet wurde.

grep blarg /etc/passwd
echo "<$?>"

Der Beendigungsstatus ist hilfreich beim Schreiben einfacher Skripte wie:

#!/bin/bash
# grep_pw: grep for a pattern in /etc/passwd
grep "$1" /etc/passwd
if [[ $? = 0 ]] ;then
  echo "Found it"
  exit 0
else
  echo "Unable to find the pattern '$1' in /etc/passwd"
  exit 1
fi

Fügen Sie diesen Text in eine Datei mit dem Namen ein grep_pw, ändern Sie ihn so, dass er mit ausführbar ist chmod 700 grep_pw, und rufen Sie ihn wie folgt auf, ./grep_pw nologinum die Zeilen zu finden, /etc/passwddie die Zeichenfolge enthalten nologin.

Als ich zum ersten Mal etwas über die Shell hörte, fand ich das folgende Skript von unschätzbarem Wert, um zu verstehen, wie die Shell Befehlszeilen analysiert und welche Befehlszeilenargumente folglich an ein Skript übergeben würden.

#!/bin/bash
# echoargs: print all the arguments
counter=1
for a in "$@" ;do
   echo "arg $counter=<$a>"
   let counter=counter+1
done

Fügen Sie diesen Inhalt in eine Datei mit dem Namen ein echoargs, ändern Sie sie so, dass sie mit ausführbar ist, chmod 700 echoargsund rufen Sie sie wie folgt auf: ./echoargs a "b c" d.

verwandte Informationen