it-swarm.com.de

Wie kann man feststellen, ob eine Zeichenfolge in einem Bash-Shell-Skript nicht definiert ist?

Wenn ich nach der Nullzeichenfolge suchen möchte, würde ich tun

[ -z $mystr ]

aber was ist, wenn ich überprüfen möchte, ob die Variable überhaupt definiert wurde? Oder gibt es keinen Unterschied beim Bash-Scripting?

148
SetJmp

Ich denke, die Antwort, nach der Sie suchen, wird impliziert (falls nicht anders angegeben) durch Vinko 's Antwort , obwohl es nicht einfach formuliert ist. Um zu unterscheiden, ob VAR gesetzt, aber leer ist oder nicht, können Sie Folgendes verwenden:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Sie können die beiden Tests in der zweiten Zeile wahrscheinlich zu einem kombinieren mit:

if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Wenn Sie jedoch die Dokumentation zu Autoconf lesen, werden Sie feststellen, dass die Kombination von Begriffen mit '-a' und die Verwendung separater einfacher Tests in Kombination mit && nicht empfohlen wird. Ich bin auf kein System gestoßen, bei dem ein Problem vorliegt. das heißt nicht, dass sie früher nicht existierten (aber heutzutage sind sie wahrscheinlich extrem selten, auch wenn sie in der fernen Vergangenheit nicht so selten waren).

Sie finden die Details dieser und anderer verwandter Shell-Parameter-Erweiterungen , test oder [ und bedingte Ausdrücke in das Bash-Handbuch.


Ich wurde vor kurzem per E-Mail zu dieser Antwort mit der Frage gefragt:

Sie verwenden zwei Tests, und ich verstehe den zweiten gut, aber nicht den ersten. Genauer gesagt verstehe ich die Notwendigkeit einer variablen Erweiterung nicht

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi

Würde das nicht das Gleiche bewirken?

if [ -z "${VAR}" ]; then echo VAR is not set at all; fi

Faire Frage - die Antwort lautet "Nein, Ihre einfachere Alternative macht nicht dasselbe".

Angenommen, ich schreibe dies vor Ihrem Test:

VAR=

Ihr Test sagt "VAR ist überhaupt nicht gesetzt", aber mein Test sagt (implizit, weil es nichts wiedergibt) "VAR ist gesetzt, aber sein Wert ist möglicherweise leer". Versuchen Sie dieses Skript:

(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:1 VAR is not set at all; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:2 VAR is not set at all; fi
)

Die Ausgabe ist:

JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all

Im zweiten Testpaar wird die Variable gesetzt, aber auf den leeren Wert gesetzt. Dies ist die Unterscheidung, die die Notationen ${VAR=value} und ${VAR:=value} treffen. Das Gleiche gilt für ${VAR-value} und ${VAR:-value} und ${VAR+value} und ${VAR:+value} und so weiter.


Wie Gili in seinem answer betont, schlägt die obige grundlegende Antwort mit set -o nounset fehl, wenn Sie bash mit der Option unbound variable ausführen. Es ist leicht zu beheben:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Oder Sie können die Option set -o nounset mit set +u abbrechen (set -u entspricht set -o nounset).

134
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~> 

-z funktioniert auch für undefinierte Variablen. Um zwischen einem undefinierten und einem definierten zu unterscheiden, verwenden Sie die aufgelisteten Dinge hier oder, mit klareren Erklärungen, hier .

Der sauberste Weg ist die Verwendung der Erweiterung wie in diesen Beispielen. Um alle Ihre Optionen zu erhalten, lesen Sie den Abschnitt Parametererweiterung im Handbuch.

Alternatives Wort:

~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED

Standardwert:

~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED

Natürlich würden Sie eine dieser Optionen anders verwenden, den gewünschten Wert anstelle des Standardwerts eingeben und die Erweiterung gegebenenfalls direkt verwenden.

37
Vinko Vrsalovic

Erweitertes Bash-Skript-Handbuch, 10.2. Parametersubstitution:

  • $ {var + blahblah}: Wenn var definiert ist, wird der Ausdruck durch 'blahblah' ersetzt, andernfalls wird null ersetzt
  • $ {var-blahblah}: Wenn var definiert ist, wird es selbst ersetzt, andernfalls wird 'blahblah' ersetzt
  • $ {var? blahblah}: Wenn var definiert ist, wird es ersetzt, ansonsten existiert die Funktion mit 'blahblah' als Fehlermeldung.


um Ihre Programmlogik darauf zu gründen, ob die Variable $ mystr definiert ist oder nicht, können Sie Folgendes tun:

isdefined=0
${mystr+ export isdefined=1}

wenn nun isdefined = 0 ist, war die Variable undefiniert. Wenn isdefined = 1 ist, wurde die Variable definiert

Diese Art der Überprüfung von Variablen ist besser als die obige Antwort, da sie eleganter und lesbarer ist. Wenn Ihre Bash-Shell so konfiguriert wurde, dass Fehler bei der Verwendung nicht definierter Variablen auftreten (set -u), Wird das Skript vorzeitig beendet.


Andere nützliche Sachen:

um $ mystr einen Standardwert von 7 zuzuweisen, falls dieser undefiniert war, und ihn ansonsten intakt zu lassen:

mystr=${mystr- 7}

um eine Fehlermeldung auszudrucken und die Funktion zu verlassen, wenn die Variable undefiniert ist:

: ${mystr? not defined}

Beachten Sie, dass ich ':' verwendet habe, um den Inhalt von $ mystr nicht als Befehl ausführen zu lassen, falls er definiert ist.

17
user854270

Eine Zusammenfassung der Tests.

[ -n "$var" ] && echo "var is set and not empty"
[ -z "$var" ] && echo "var is unset or empty"
[ "${var+x}" = "x" ] && echo "var is set"  # may or may not be empty
[ -n "${var+x}" ] && echo "var is set"  # may or may not be empty
[ -z "${var+x}" ] && echo "var is unset"
[ -z "${var-x}" ] && echo "var is set and empty"
9
k107

https://stackoverflow.com/a/9824943/14731 enthält eine bessere Antwort (eine, die besser lesbar ist und mit aktiviertem set -o nounset funktioniert). Es funktioniert ungefähr so:

if [ -n "${VAR-}" ]; then
    echo "VAR is set and is not empty"
Elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then
    echo "VAR is set, but empty"
else
    echo "VAR is not set"
fi
5
Gili

Die explizite Möglichkeit, nach einer zu definierenden Variablen zu suchen, ist:

[ -v mystr ]
4
Felix Leipold

Das Bash Reference Manual ist eine maßgebliche Informationsquelle zu bash.

Hier ist ein Beispiel für das Testen einer Variablen, um festzustellen, ob sie vorhanden ist:

if [ -z "$PS1" ]; then
        echo This Shell is not interactive
else
        echo This Shell is interactive
fi

(Von Abschnitt 6.3.2 .)

Beachten Sie, dass das Leerzeichen nach dem offenen [ Und vor dem ] nicht optional ist.


Tipps für Vim-Benutzer

Ich hatte ein Skript mit folgenden Deklarationen:

export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"

Aber ich wollte, dass sie sich auf bestehende Werte berufen. Also habe ich sie so umgeschrieben:

if [ -z "$VARIABLE_NAME" ]; then
        export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
fi

Ich konnte dies in vim mit einem schnellen regulären Ausdruck automatisieren:

s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r  export \1=\2\rfi\r/gc

Dies kann angewendet werden, indem Sie die entsprechenden Zeilen visuell auswählen und dann : Eingeben. Die Befehlsleiste wird mit :'<,'> Vorbelegt. Fügen Sie den obigen Befehl ein und drücken Sie die Eingabetaste.


Getestet auf dieser Version von Vim:

VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58)
Compiled by [email protected]

Windows-Benutzer möchten möglicherweise unterschiedliche Zeilenenden.

1
funroll

eine andere Option: die Erweiterung "Listenarray-Indizes" :

$ unset foo
$ foo=
$ echo ${!foo[*]}
0
$ foo=bar
$ echo ${!foo[*]}
0
$ foo=(bar baz)
$ echo ${!foo[*]}
0 1

das einzige Mal, dass dies zu einer leeren Zeichenkette erweitert wird, ist, wenn foo nicht gesetzt ist. Sie können dies also mit der Zeichenkettenbedingung überprüfen:

$ unset foo
$ [[ ${!foo[*]} ]]; echo $?
1
$ foo=
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=bar
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=(bar baz)
$ [[ ${!foo[*]} ]]; echo $?
0

sollte in jeder bash-version> = 3.0 verfügbar sein

1
Aaron Davies

dieses Fahrrad nicht noch weiter zu vergießen, sondern hinzufügen wollte

shopt -s -o nounset

ist etwas, das Sie am Anfang eines Skripts anfügen können. Dies tritt auf, wenn die Variablen nicht an einer beliebigen Stelle im Skript deklariert sind. Die Meldung, die Sie sehen würden, lautet unbound variable, Aber wie andere erwähnen, wird kein leerer String oder Nullwert abgefangen. Um sicherzustellen, dass ein einzelner Wert nicht leer ist, können wir eine Variable testen, die mit ${mystr:?}, Auch als Dollarzeichenerweiterung bezeichnet, erweitert wird, was mit parameter null or not set Zu Fehlern führen würde.

1
Sacrilicious

Folgendes ist meiner Meinung nach ein viel klarerer Weg, um zu überprüfen, ob eine Variable definiert ist:

var_defined() {
    local var_name=$1
    set | grep "^${var_name}=" 1>/dev/null
    return $?
}

Verwenden Sie es wie folgt:

if var_defined foo; then
    echo "foo is defined"
else
    echo "foo is not defined"
fi
0
Swiss