523 Stimmen

Wie kann man kurz und bündig überprüfen, ob Umgebungsvariablen in einem Unix-Shell-Skript gesetzt sind?

Ich habe ein paar Unix-Shell-Skripte, bei denen ich überprüfen muss, ob bestimmte Umgebungsvariablen gesetzt sind, bevor ich mit der Arbeit beginne, also mache ich so etwas:

if [ -z "$STATE" ]; then
    echo "Need to set STATE"
    exit 1
fi  

if [ -z "$DEST" ]; then
    echo "Need to set DEST"
    exit 1
fi

was eine Menge Tipparbeit ist. Gibt es ein eleganteres Idiom, um zu überprüfen, ob ein Satz von Umgebungsvariablen gesetzt ist?

EDIT: Ich sollte erwähnen, dass diese Variablen keinen sinnvollen Standardwert haben - das Skript sollte fehlschlagen, wenn eine davon nicht gesetzt ist.

2 Stimmen

Viele der Antworten auf diese Frage wirken wie etwas, das man auf Code Golf Stack Exchange .

614voto

Jonathan Leffler Punkte 694013

Parameter Erweiterung

Die offensichtliche Antwort ist die Verwendung einer der Sonderformen der Parametererweiterung:

: ${STATE?"Need to set STATE"}
: ${DEST:?"Need to set DEST non-empty"}

Oder besser (siehe Abschnitt "Position der doppelten Anführungszeichen" unten):

: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"

Die erste Variante (mit nur ? ) erfordert, dass STATE gesetzt wird, aber STATE="" (eine leere Zeichenkette) ist OK - nicht genau das, was Sie wollen, aber die alternative und ältere Notation.

Die zweite Variante (mit :? ) erfordert, dass DEST gesetzt und nicht leer ist.

Wenn Sie keine Nachricht angeben, gibt die Shell eine Standardnachricht aus.

Le site ${var?} construct ist portabel bis zur Version 7 von UNIX und der Bourne Shell (1978 oder so ähnlich). Die ${var:?} Konstrukt ist etwas jüngeren Datums: Ich glaube, es war in System III UNIX um 1981, aber vielleicht war es auch schon vorher in PWB UNIX. Es ist daher in der Korn-Shell und in den POSIX-Shells enthalten, insbesondere in der Bash.

Sie ist normalerweise in der Manpage der Shell in einem Abschnitt namens Parameter Erweiterung . Zum Beispiel die bash sagt das Handbuch:

${parameter:?word}

Fehler anzeigen, wenn Null oder nicht gesetzt. Wenn der Parameter null oder nicht gesetzt ist, wird die Erweiterung von word (oder eine entsprechende Meldung, wenn word nicht vorhanden ist) in den Standardfehler geschrieben und die Shell, falls sie nicht interaktiv ist, beendet. Andernfalls wird der Wert des Parameters ersetzt.

Der Colon-Befehl

Ich sollte vielleicht noch hinzufügen, dass der Doppelpunkt-Befehl einfach seine Argumente auswertet und dann erfolgreich ist. Es ist die ursprüngliche Shell-Kommentarschreibweise (vor ' # ' an das Ende der Zeile). Lange Zeit hatten die Skripte der Bourne-Shell einen Doppelpunkt als erstes Zeichen. Die C-Shell würde ein Skript lesen und anhand des ersten Zeichens feststellen, ob es für die C-Shell bestimmt war (ein ' # ' Hash) oder die Bourne-Shell (ein ' : ' Doppelpunkt). Dann kam der Kernel ins Spiel und fügte Unterstützung für ' #!/path/to/program ' und die Bourne-Shell erhielt ' # Kommentare, und die Konvention des Doppelpunkts blieb auf der Strecke. Aber wenn Sie auf ein Skript stoßen, das mit einem Doppelpunkt beginnt, wissen Sie jetzt, warum.


Position der doppelten Anführungszeichen

blong fragte in einer Kommentar :

Haben Sie eine Meinung zu dieser Diskussion? https://github.com/koalaman/shellcheck/issues/380#issuecomment-145872749

Das ist der Kern der Diskussion:

Wenn ich jedoch shellcheck es (mit Version 0.4.1), erhalte ich diese Meldung:

In script.sh line 13:
: ${FOO:?"The environment variable 'FOO' must be set and non-empty"}
  ^-- SC2086: Double quote to prevent globbing and word splitting.

Gibt es einen Rat, was ich in diesem Fall tun sollte?

Die kurze Antwort lautet: "Tu, was du willst shellcheck schlägt vor":

: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"

Um dies zu verdeutlichen, sollten Sie sich folgendes ansehen. Beachten Sie, dass die : Befehl gibt seine Argumente nicht als Echo aus (aber die Shell wertet die Argumente aus). Wir wollen die Argumente sehen, daher verwendet der folgende Code printf "%s\n" anstelle von : .

$ mkdir junk
$ cd junk
$ > abc
$ > def
$ > ghi
$ 
$ x="*"
$ printf "%s\n" ${x:?You must set x}    # Careless; not recommended
abc
def
ghi
$ unset x
$ printf "%s\n" ${x:?You must set x}    # Careless; not recommended
bash: x: You must set x
$ printf "%s\n" "${x:?You must set x}"  # Careful: should be used
bash: x: You must set x
$ x="*"
$ printf "%s\n" "${x:?You must set x}"  # Careful: should be used
*
$ printf "%s\n" ${x:?"You must set x"}  # Not quite careful enough
abc
def
ghi
$ x=
$ printf "%s\n" ${x:?"You must set x"}  # Not quite careful enough
bash: x: You must set x
$ unset x
$ printf "%s\n" ${x:?"You must set x"}  # Not quite careful enough
bash: x: You must set x
$ 

Beachten Sie, dass der Wert in $x wird zunächst erweitert um * und dann eine Liste von Dateinamen, wenn der Gesamtausdruck nicht in Anführungszeichen steht. Das ist es, was shellcheck empfohlen wird, behoben werden sollte. Ich habe nicht überprüft, ob die Form, bei der der Ausdruck in doppelte Anführungszeichen eingeschlossen ist, nicht zu beanstanden ist, aber es ist eine vernünftige Annahme, dass es OK wäre.

3 Stimmen

Das ist es, was ich brauche. Ich benutze verschiedene Versionen von Unix seit 1987 und habe diese Syntax noch nie gesehen - das zeigt nur, dass ich...

0 Stimmen

Wie funktioniert das und wo ist es dokumentiert? Ich frage mich, ob es geändert werden kann, um zu prüfen, ob die Variable existiert und auf einen bestimmten Wert gesetzt ist.

8 Stimmen

Sie ist in der Shell-Handbuchseite oder im Bash-Handbuch dokumentiert, normalerweise unter der Überschrift 'Parameter Expansion'. Der Standardweg, um zu prüfen, ob die Variable existiert und auf einen bestimmten Wert gesetzt ist (sagen wir 'abc'), ist einfach: if [ "$variable" = "abc" ]; then : OK; else : variable is not set correctly; fi .

146voto

David Schlosnagle Punkte 4243

Versuchen Sie dies:

[ -z "$STATE" ] && echo "Need to set STATE" && exit 1;

9 Stimmen

Das ist ziemlich langatmig. Das Semikolon ist überflüssig.

3 Stimmen

Oder noch kürzer [ -z "$STATE" ] && { echo "Need to set STATE"; exit 1; } siehe dieser Blogbeitrag

43 Stimmen

Was das ist, ist lesbar. Ich bin ganz dafür. Bash-Skripte brauchen alle Hilfe, die sie in dieser Abteilung bekommen können!

56voto

Rob Wells Punkte 35303

Ihre Frage hängt von der von Ihnen verwendeten Shell ab.

Die Bourne-Shell lässt nur sehr wenig von dem übrig, was Sie suchen.

ABER...

Es funktioniert, und zwar fast überall.

Versuchen Sie einfach, sich von csh fernzuhalten. Sie war gut für den Schnickschnack, den sie im Vergleich zur Bourne-Shell hinzufügte, aber jetzt knarrt sie wirklich. Wenn Sie mir nicht glauben, versuchen Sie einfach, STDERR in csh zu trennen! (-:

Hier gibt es zwei Möglichkeiten. Das obige Beispiel, nämlich mit:

${MyVariable:=SomeDefault}

müssen Sie zum ersten Mal auf $MyVariable verweisen. Dies nimmt die Umgebungsvariable MyVariable und weist der Variablen für die spätere Verwendung den Wert von SomeDefault zu, wenn dieser derzeit nicht gesetzt ist.

Sie haben auch die Möglichkeit,:

${MyVariable:-SomeDefault}

die einfach SomeDefault durch die Variable ersetzt, in der Sie dieses Konstrukt verwenden. Der Variablen wird nicht der Wert SomeDefault zugewiesen, und der Wert von MyVariable ist nach dem Auftreten dieser Anweisung immer noch null.

3 Stimmen

CSH: ( foo > foo.out ) >& foo.err

0 Stimmen

Die Bourne-Shell tut, was nötig ist.

54voto

Paul Makkar Punkte 547

Der einfachste Ansatz ist sicherlich das Hinzufügen der -u zum Shebang (die Zeile am Anfang Ihres Skripts) wechseln, vorausgesetzt, Sie verwenden bash :

#!/bin/sh -u

Dies führt dazu, dass das Skript beendet wird, wenn sich darin ungebundene Variablen befinden.

40voto

${MyVariable:=SomeDefault}

Si MyVariable gesetzt ist und nicht null, wird der Wert der Variablen zurückgesetzt (= es passiert nichts).
Sonst, MyVariable wird eingestellt auf SomeDefault .

Der obige Befehl versucht, Folgendes auszuführen ${MyVariable} Wenn Sie also nur die Variable setzen wollen, tun Sie das:

MyVariable=${MyVariable:=SomeDefault}

0 Stimmen

Dadurch wird die Meldung nicht erzeugt - und die Frage besagt, dass es keinen Standardwert gibt (obwohl das nicht gesagt wurde, als Sie Ihre Antwort eingegeben haben).

10 Stimmen

Richtige Versionen: (1) : ${MyVariable:=SomeDefault} oder (2) : MyVariable=${MyVariable:-SomeDefault}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X