Testen Sie, ob eine Variable in bash gesetzt ist, wenn Sie "set -o nounset" verwenden.

94

Der folgende Code wird mit einem ungebundenen Variablenfehler beendet. Wie kann set -oich das beheben, während ich immer noch die Nomen-Set-Option verwende?

#!/bin/bash

set -o nounset

if [ ! -z ${WHATEVER} ];
 then echo "yo"
fi

echo "whatever"
Vinodkone
quelle

Antworten:

97
#!/bin/bash

set -o nounset


VALUE=${WHATEVER:-}

if [ ! -z ${VALUE} ];
 then echo "yo"
fi

echo "whatever"

In diesem Fall handelt es VALUEsich um eine leere Zeichenfolge, wenn diese WHATEVERnicht festgelegt ist. Wir verwenden die {parameter:-word}Erweiterung, die Sie man bashunter "Parametererweiterung" nachschlagen können .

Angelom
quelle
14
einfach ersetzen, wenn [! -z $ {VALUE}]; mit wenn [! -z $ {WHATEVER: -}];
Angelom
18
:-prüft, ob die Variable nicht gesetzt oder leer ist. Wenn Sie nur überprüfen möchten, ob es nicht gesetzt ist, verwenden Sie -: VALUE=${WHATEVER-}. Eine besser lesbare Methode, um zu überprüfen, ob eine Variable leer ist:if [ "${WHATEVER+defined}" = defined ]; then echo defined; else echo undefined; fi
l0b0
1
Dies funktioniert auch nicht, wenn es $WHATEVERnur Leerzeichen enthält - siehe meine Antwort.
10b0
9
Gibt es einen Grund, " ! -z" statt nur " -n" zu verwenden?
Jonathan Hartley
31

Sie müssen die Variablen in Anführungszeichen setzen, wenn Sie das erwartete Ergebnis erzielen möchten:

check() {
    if [ -n "${WHATEVER-}" ]
    then
        echo 'not empty'
    elif [ "${WHATEVER+defined}" = defined ]
    then
        echo 'empty but defined'
    else
        echo 'unset'
    fi
}

Prüfung:

$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER='   '
$ check
not empty
l0b0
quelle
Ich habe es versucht und bin überrascht, dass dies funktioniert ... Alles ist korrekt, außer laut "info bash", "${WHATEVER-}"sollte ein ":"(Doppelpunkt) vor dem "-"(Bindestrich) wie: "${WHATEVER:-}"und "${WHATEVER+defined}"ein Doppelpunkt vor dem "+"(Plus) wie: stehen "${WHATEVER:+defined}". Bei mir funktioniert es so oder so, mit oder ohne Doppelpunkt. Bei einigen Versionen von 'nix wird es wahrscheinlich nicht funktionieren, ohne den Doppelpunkt einzuschließen, daher sollte es wahrscheinlich hinzugefügt werden.
Kevin Fegan
8
Nö, -, +, :+, und :-werden unterstützt. Die ersteren erkennen, ob die Variable gesetzt ist , und die letzteren erkennen, ob sie gesetzt oder leer ist . Von man bash: "Das Weglassen des Doppelpunkts führt zu einem Test nur für einen Parameter, der nicht festgelegt ist."
10.
1
Nevermind =). Du hast Recht. Ich weiß nicht, wie ich das verpasst habe.
Kevin Fegan
Aus den Dokumenten : Anders ausgedrückt: Wenn der Doppelpunkt enthalten ist, prüft der Operator, ob beide Parameter vorhanden sind und ob ihr Wert nicht null ist. Wenn der Doppelpunkt weggelassen wird, prüft der Bediener nur die Existenz.
Acumenus
8

Wie wäre es mit einem Oneliner?

[ -z "${VAR:-}" ] && echo "VAR is not set or is empty" || echo "VAR is set to $VAR"

-z prüft beide auf leere oder nicht gesetzte Variable

NublaII
quelle
2
Nein, -zprüft nur, ob der nächste Parameter leer ist. -zDies ist nur ein Argument des [Befehls. Die variable Erweiterung erfolgt, bevor [ -zetwas getan werden kann.
Dolmen
1
Dies scheint insofern die richtige Lösung zu sein, als es keinen Fehler erzeugt, wenn $ VAR nicht gesetzt ist. @dolmen können Sie ein Beispiel dafür geben, wann es nicht funktionieren würde?
Chris Stryczynski
@dolmen Nachdem ich verschiedene Bash-Ressourcen über die Param-Erweiterung gelesen und die anderen Antworten als zu kompliziert empfunden habe, sehe ich nichts Falsches an dieser. Daher erscheint Ihre „Klarstellung“, obwohl sie technisch korrekt ist, in der Praxis eher sinnlos, es sei denn, Sie müssen zwischen nicht gesetzt und leer unterscheiden. Ich habe nicht gesetzt, leer und nicht leer getestet (Bash 4) und es hat ziemlich genau das getan, was jedes Mal beworben wurde.
JL Peyret
8

Annahmen:

$ echo $SHELL
/bin/bash
$ /bin/bash --version | head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
$ set -o nounset

Wenn ein nicht interaktives Skript einen Fehler drucken und beenden soll, wenn eine Variable null ist oder nicht festgelegt ist:

$ [[ "${HOME:?}" ]]

$ [[ "${IAMUNBOUND:?}" ]]
bash: IAMUNBOUND: parameter null or not set

$ IAMNULL=""
$ [[ "${IAMNULL:?}" ]]
bash: IAMNULL: parameter null or not set

Wenn Sie nicht möchten, dass das Skript beendet wird:

$ [[ "${HOME:-}" ]] || echo "Parameter null or not set."

$ [[ "${IAMUNBOUND:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

$ IAMNULL=""
$ [[ "${IAMUNNULL:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

Sie können sogar [und ]anstelle von [[und ]]darüber verwenden, aber letzteres ist in Bash vorzuziehen.

Beachten Sie, was der Doppelpunkt oben tut. Aus den Dokumenten :

Anders ausgedrückt, wenn der Doppelpunkt enthalten ist, prüft der Operator, ob beide Parameter vorhanden sind und ob ihr Wert nicht null ist. Wenn der Doppelpunkt weggelassen wird, prüft der Bediener nur die Existenz.

Es besteht anscheinend keine Notwendigkeit für -noder -z.

Zusammenfassend kann ich normalerweise nur verwenden [[ "${VAR:?}" ]]. In den Beispielen wird ein Fehler ausgegeben und beendet, wenn eine Variable null ist oder nicht gesetzt ist.

Scharfsinn
quelle
4

Sie können verwenden

if [[ ${WHATEVER:+$WHATEVER} ]]; then

aber

if [[ "${WHATEVER:+isset}" == "isset" ]]; then

könnte besser lesbar sein.

Aleš Friedl
quelle
Zeichenfolgenvergleiche sollten den Standardoperator (POSIX) verwenden =, ==um die Portabilität nicht zu verbessern , und [nicht, [[wenn möglich.
Jens
2
@Jens Die Frage ist spezifisch für Bash und beinhaltet, set -o nounsetwelche spezifisch für Bash ist. Wenn Sie ein #!/bin/bashoben in Ihr Skript einfügen, ist es am besten, die Verbesserungen von bash zu verwenden.
Bruno Bronosky
0

Obwohl dies nicht genau der oben angeforderte Anwendungsfall ist, habe ich festgestellt, dass wenn Sie nounset(oder -u) das Standardverhalten verwenden möchten, das Sie möchten: Beenden ungleich Null mit einer beschreibenden Nachricht.

Es dauerte lange genug, bis mir klar wurde, dass es sich lohnte, es als Lösung zu veröffentlichen.

Wenn Sie beim Beenden nur etwas anderes wiederholen oder eine Bereinigung durchführen möchten, können Sie eine Falle verwenden.

Der :-Operator ist wahrscheinlich das, was Sie sonst wollen.

Max Bileschi
quelle