Bitte haben Sie die Angewohnheit, [-z "$ mystr"] im Gegensatz zu [-z $ mystr] zu verwenden
Charles Duffy
Wie macht man das Gegenteil? Ich meine, wenn die Zeichenfolge nicht null ist
Öffnen Sie den Weg
1
@flow: Was ist mit[ -n "${VAR+x}"] && echo not null
Lekensteyn
1
@ CharlesDuffy Ich habe dies bereits in vielen Online-Ressourcen gelesen. Warum ist das bevorzugt?
Ffledgling
6
@Ayos, denn wenn Sie keine Anführungszeichen haben, wird der Inhalt der Variablen in Zeichenfolgen aufgeteilt und globalisiert. Wenn es eine leere Zeichenfolge ist, wird es [ -z ]anstelle von [ -z "" ]; wenn es Leerzeichen hat, wird es [ -z "my" "test" ]statt [ -z my test ]; und wenn ja [ -z * ], wird das *durch die Namen der Dateien in Ihrem Verzeichnis ersetzt.
Charles Duffy
Antworten:
138
Ich denke , die Antwort , die Sie nach sind impliziert (wenn nicht angegeben) von Vinko ‚s Antwort , obwohl es einfach nicht ausgeschrieben ist. Um zu unterscheiden, ob VAR festgelegt, aber leer oder nicht festgelegt ist, können Sie Folgendes verwenden:
if[-z "${VAR+xxx}"];then echo VAR is not set at all;fiif[-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' nicht empfohlen wird und die Verwendung separater einfacher Tests in Kombination mit ' ' empfohlen wird &&. Ich bin nicht auf ein System gestoßen, bei dem ein Problem vorliegt. das bedeutet nicht, dass sie früher nicht existierten (aber sie sind heutzutage wahrscheinlich extrem selten, auch wenn sie in der fernen Vergangenheit nicht so selten waren).
Ich wurde kürzlich per E-Mail nach 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 dies nicht dasselbe 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 meiner 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;fiif[-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;fiif[-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 ${VAR=value}und ${VAR:=value}Notationen machen. Das Gleiche gilt für ${VAR-value}und ${VAR:-value}und ${VAR+value}und ${VAR:+value}und und so weiter.
Wie Gili in seiner Antwort betont, schlägt die obige grundlegende Antwort mit fehl , wenn Sie bashmit der set -o nounsetOption arbeiten unbound variable. Es ist leicht zu beheben:
if[-z "${VAR+xxx}"];then echo VAR is not set at all;fiif[-z "${VAR-}"]&&["${VAR+xxx}"="xxx"];then echo VAR is set but empty;fi
Oder Sie können die set -o nounsetOption mit abbrechen set +u( set -uentspricht set -o nounset).
Das einzige Problem, das ich mit dieser Antwort habe, ist, dass sie ihre Aufgabe eher indirekt und unklar erfüllt.
Schweizer
3
Wenn Sie auf der Bash-Manpage nach der Beschreibung der oben genannten Bedeutung suchen möchten, lesen Sie den Abschnitt "Parametererweiterung" und dann den folgenden Text: "Wenn Sie keine Teilstringerweiterung durchführen, verwenden Sie die unten dokumentierten Formulare für Bash-Tests Ein Parameter, der nicht gesetzt oder null ist ['null' bedeutet die leere Zeichenfolge]. Das Weglassen des Doppelpunkts führt nur zu einem Test für einen Parameter, der nicht gesetzt ist (...) $ {parameter: + word}: Verwenden Sie den alternativen Wert. If-Parameter ist null oder nicht gesetzt, nichts wird ersetzt, andernfalls wird die Erweiterung des Wortes ersetzt. "
David Tonhofer
2
@Schweiz Das ist weder unklar noch indirekt, sondern idiomatisch. Vielleicht für einen Programmierer, der nicht vertraut ist ${+}und der ${-}unklar ist, aber die Vertrautheit mit diesen Konstrukten ist wesentlich, wenn man ein kompetenter Benutzer der Shell sein will.
Ich habe viele Tests durchgeführt; weil die Ergebnisse in meinen Skripten inkonsistent waren. Ich schlage vor, dass die Leute den " [ -v VAR ]" -Ansatz mit bash -s v4.2 und darüber hinaus untersuchen .
-z funktioniert auch für undefinierte Variablen. Um zwischen einem undefinierten und einem definierten zu unterscheiden, verwenden Sie die hier oder mit klareren Erklärungen hier aufgeführten Dinge .
Am saubersten ist die Verwendung der Erweiterung wie in diesen Beispielen. Um alle 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 einen dieser Werte anders verwenden, indem Sie den gewünschten Wert anstelle des Standardwerts verwenden und die Erweiterung gegebenenfalls direkt verwenden.
Aber ich möchte unterscheiden, ob die Zeichenfolge "" ist oder noch nie definiert wurde. Ist das möglich?
Setjmp
1
Diese Antwort zeigt , wie man zwischen diesen beiden Fällen unterscheidet. Folgen Sie dem Link zur Bash-FAQ, um weitere Informationen zu erhalten.
Charles Duffy
1
Ich fügte hinzu, dass nach seinem Kommentar Charles
Vinko Vrsalovic
2
Suchen Sie in der Bash-Manpage nach "Parametererweiterung" für all diese "Tricks". ZB $ {foo: -default}, um einen Standardwert zu verwenden, $ {foo: = default}, um den Standardwert zuzuweisen, $ {foo :? Fehlermeldung}, um eine Fehlermeldung anzuzeigen, wenn foo nicht gesetzt ist usw.
$ {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, andernfalls existiert die Funktion mit 'blahblah' als Fehlermeldung.
Um Ihre Programmlogik darauf zu stützen, 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 bei der Verwendung undefinierter Variablen Fehler auftreten (set -u), wird das Skript vorzeitig beendet.
Andere nützliche Dinge:
Um $ mystr einen Standardwert von 7 zuzuweisen, wenn er nicht definiert war, und ihn ansonsten intakt zu lassen:
mystr=${mystr-7}
So drucken Sie eine Fehlermeldung und beenden die Funktion, wenn die Variable undefiniert ist:
: ${mystr? not defined}
Beachten Sie hier, dass ich ':' verwendet habe, um den Inhalt von $ mystr nicht als Befehl auszuführen, falls er definiert ist.
Ich wusste nichts über das? Syntax für BASH-Variablen. Das ist ein schöner Fang.
Schweizer
Dies funktioniert auch mit indirekten Variablenreferenzen. Dies geht vorbei: var= ; varname=var ; : ${!varname?not defined}und dies endet : varname=var ; : ${!varname?not defined}. Aber es ist eine gute Angewohnheit, set -udie das Gleiche viel einfacher macht.
Ceving
11
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"
Gute Praxis in Bash. Manchmal haben Dateipfade Leerzeichen oder zum Schutz vor Befehlsinjektion
k107
1
Ich denke , mit ${var+x}ihm nicht notwendig , außer, wenn variable Namen dürfen in ihnen Räume haben.
Anne van Rossum
Nicht nur gute Praxis; es ist erforderlich , mit [richtigen Ergebnisse zu erzielen. Wenn varnicht gesetzt oder leer, [ -n $var ]reduziert sich auf [ -n ]den Exit-Status 0, während [ -n "$var" ]der erwartete (und korrekte) Exit-Status von 1 hat.
chepner
5
https://stackoverflow.com/a/9824943/14731 enthält eine bessere Antwort (eine, die besser lesbar ist und mit set -o nounsetaktiviert 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
Sie können dies in keiner der Manpages finden (für Bash oder Test), aber es funktioniert für mich. Haben Sie eine Idee, welche Versionen dies hinzugefügt wurde?
Ash Berlin-Taylor
1
Es ist in Bedingten Ausdrücken dokumentiert , auf die der testBediener am Ende des Abschnitts Bourne Shell Builtins verweist . Ich weiß nicht, wann es hinzugefügt wurde, aber es ist nicht in der Apple-Version von bash(basierend auf bash3.2.51) enthalten, daher handelt es sich wahrscheinlich um eine 4.x-Funktion.
Jonathan Leffler
1
Das funktioniert bei mir nicht GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu). Der Fehler ist -bash: [: -v: unary operator expected. Laut einem Kommentar hier ist mindestens Bash 4.2 erforderlich, um zu funktionieren.
Acumenus
Vielen Dank für die Überprüfung, wann es verfügbar wurde. Ich hatte es schon einmal auf verschiedenen Systemen verwendet, aber dann funktionierte es plötzlich nicht mehr. Ich bin aus Neugier hierher gekommen und ja, natürlich ist die Bash auf diesem System eine 3.x Bash.
Das einzige Mal, wenn dies auf die leere Zeichenfolge erweitert wird, ist, wenn fooes nicht festgelegt ist. Sie können es also mit der Zeichenfolgenbedingung überprüfen:
dieses Fahrrad nicht noch weiter zu vergießen, wollte aber hinzufügen
shopt -s -o nounset
ist etwas, das Sie am Anfang eines Skripts hinzufügen können. Dieser Fehler tritt auf, wenn Variablen an keiner Stelle im Skript deklariert werden. Die Nachricht, die Sie sehen würden, ist unbound variable, aber wie andere erwähnen, wird keine leere Zeichenfolge oder kein Nullwert abgefangen. Um sicherzustellen, dass ein einzelner Wert nicht leer ist, können wir eine Variable testen, mit der sie erweitert wird ${mystr:?}, auch als Dollarzeichenerweiterung bezeichnet, was zu Fehlern führen würde parameter null or not set.
Dies kann angewendet werden, indem die relevanten Zeilen visuell ausgewählt und dann eingegeben werden :. Die Befehlsleiste wird mit gefüllt :'<,'>. Fügen Sie den obigen Befehl ein und drücken Sie die Eingabetaste.
Getestet auf dieser Version von Vim:
VIM -ViIMproved7.3(2010Aug15, compiled Aug22201515:38:58)Compiled by root@apple.com
Eine Funktion zu schreiben ist keine schlechte Idee; anrufen grepist schrecklich. Beachten Sie, dass bashStützen ${!var_name}als Weg , um den Wert einer Variablen des Erhaltens , dessen Name in angegeben $var_name, so name=value; value=1; echo ${name} ${!name}Ausbeuten value 1.
Jonathan Leffler
0
Eine kürzere Version zum Testen undefinierter Variablen kann einfach sein:
call set ohne Argumente. Es gibt alle definierten Variablen aus.
Die letzten in der Liste sind die in Ihrem Skript definierten.
Sie können also die Ausgabe an etwas weiterleiten, das herausfinden kann, welche Dinge definiert sind und welche nicht
Ich habe das nicht herabgestimmt, aber es ist so etwas wie ein Vorschlaghammer, eine ziemlich kleine Nuss zu knacken.
Jonathan Leffler
Diese Antwort gefällt mir tatsächlich besser als die akzeptierte Antwort. Es ist klar, was in dieser Antwort getan wird. Die akzeptierte Antwort ist höllisch wackelig.
Schweizer
Es scheint, dass diese Antwort eher ein Nebeneffekt der Implementierung von "set" ist als etwas, das wünschenswert ist.
[ -n "${VAR+x}"] && echo not null
[ -z ]
anstelle von[ -z "" ]
; wenn es Leerzeichen hat, wird es[ -z "my" "test" ]
statt[ -z my test ]
; und wenn ja[ -z * ]
, wird das*
durch die Namen der Dateien in Ihrem Verzeichnis ersetzt.Antworten:
Ich denke , die Antwort , die Sie nach sind impliziert (wenn nicht angegeben) von Vinko ‚s Antwort , obwohl es einfach nicht ausgeschrieben ist. Um zu unterscheiden, ob VAR festgelegt, aber leer oder nicht festgelegt ist, können Sie Folgendes verwenden:
Sie können die beiden Tests in der zweiten Zeile wahrscheinlich zu einem kombinieren mit:
Wenn Sie jedoch die Dokumentation zu Autoconf lesen, werden Sie feststellen, dass die Kombination von Begriffen mit '
-a
' nicht empfohlen wird und die Verwendung separater einfacher Tests in Kombination mit ' ' empfohlen wird&&
. Ich bin nicht auf ein System gestoßen, bei dem ein Problem vorliegt. das bedeutet nicht, dass sie früher nicht existierten (aber sie sind heutzutage wahrscheinlich extrem selten, auch wenn sie in der fernen Vergangenheit nicht so selten waren).Einzelheiten zu diesen und anderen verwandten Shell-Parametererweiterungen , den Befehlen
test
oder[
und den bedingten Ausdrücken finden Sie im Bash-Handbuch.Ich wurde kürzlich per E-Mail nach dieser Antwort mit der Frage gefragt:
Faire Frage - die Antwort lautet "Nein, Ihre einfachere Alternative macht nicht dasselbe".
Angenommen, ich schreibe dies vor Ihrem Test:
Ihr Test sagt "VAR ist überhaupt nicht gesetzt", aber meiner sagt (implizit, weil es nichts wiedergibt) "VAR ist gesetzt, aber sein Wert ist möglicherweise leer". Versuchen Sie dieses Skript:
Die Ausgabe ist:
Im zweiten Testpaar wird die Variable gesetzt, aber auf den leeren Wert gesetzt. Dies ist die Unterscheidung, die die
${VAR=value}
und${VAR:=value}
Notationen machen. Das Gleiche gilt für${VAR-value}
und${VAR:-value}
und${VAR+value}
und${VAR:+value}
und und so weiter.Wie Gili in seiner Antwort betont, schlägt die obige grundlegende Antwort mit fehl , wenn Sie
bash
mit derset -o nounset
Option arbeitenunbound variable
. Es ist leicht zu beheben:Oder Sie können die
set -o nounset
Option mit abbrechenset +u
(set -u
entsprichtset -o nounset
).quelle
${+}
und der${-}
unklar ist, aber die Vertrautheit mit diesen Konstrukten ist wesentlich, wenn man ein kompetenter Benutzer der Shell sein will.set -o nounset
aktiviertem Gerät implementieren möchten .[ -v VAR ]
" -Ansatz mit bash -s v4.2 und darüber hinaus untersuchen .-z funktioniert auch für undefinierte Variablen. Um zwischen einem undefinierten und einem definierten zu unterscheiden, verwenden Sie die hier oder mit klareren Erklärungen hier aufgeführten Dinge .
Am saubersten ist die Verwendung der Erweiterung wie in diesen Beispielen. Um alle Optionen zu erhalten, lesen Sie den Abschnitt Parametererweiterung im Handbuch.
Alternatives Wort:
Standardwert:
Natürlich würden Sie einen dieser Werte anders verwenden, indem Sie den gewünschten Wert anstelle des Standardwerts verwenden und die Erweiterung gegebenenfalls direkt verwenden.
quelle
Advanced Bash Scripting Guide, 10.2. Parameterersetzung:
Um Ihre Programmlogik darauf zu stützen, ob die Variable $ mystr definiert ist oder nicht, können Sie Folgendes tun:
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 bei der Verwendung undefinierter Variablen Fehler auftreten
(set -u)
, wird das Skript vorzeitig beendet.Andere nützliche Dinge:
Um $ mystr einen Standardwert von 7 zuzuweisen, wenn er nicht definiert war, und ihn ansonsten intakt zu lassen:
So drucken Sie eine Fehlermeldung und beenden die Funktion, wenn die Variable undefiniert ist:
Beachten Sie hier, dass ich ':' verwendet habe, um den Inhalt von $ mystr nicht als Befehl auszuführen, falls er definiert ist.
quelle
var= ; varname=var ; : ${!varname?not defined}
und dies endet :varname=var ; : ${!varname?not defined}
. Aber es ist eine gute Angewohnheit,set -u
die das Gleiche viel einfacher macht.Eine Zusammenfassung der Tests.
quelle
${var+x}
ihm nicht notwendig , außer, wenn variable Namen dürfen in ihnen Räume haben.[
richtigen Ergebnisse zu erzielen. Wennvar
nicht gesetzt oder leer,[ -n $var ]
reduziert sich auf[ -n ]
den Exit-Status 0, während[ -n "$var" ]
der erwartete (und korrekte) Exit-Status von 1 hat.https://stackoverflow.com/a/9824943/14731 enthält eine bessere Antwort (eine, die besser lesbar ist und mit
set -o nounset
aktiviert funktioniert ). Es funktioniert ungefähr so:quelle
Die explizite Möglichkeit, nach einer zu definierenden Variablen zu suchen, wäre:
quelle
test
Bediener am Ende des Abschnitts Bourne Shell Builtins verweist . Ich weiß nicht, wann es hinzugefügt wurde, aber es ist nicht in der Apple-Version vonbash
(basierend aufbash
3.2.51) enthalten, daher handelt es sich wahrscheinlich um eine 4.x-Funktion.GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
. Der Fehler ist-bash: [: -v: unary operator expected
. Laut einem Kommentar hier ist mindestens Bash 4.2 erforderlich, um zu funktionieren.eine weitere Option: die Erweiterung "Listenarray-Indizes" :
Das einzige Mal, wenn dies auf die leere Zeichenfolge erweitert wird, ist, wenn
foo
es nicht festgelegt ist. Sie können es also mit der Zeichenfolgenbedingung überprüfen:sollte in jeder Bash-Version> = 3.0 verfügbar sein
quelle
dieses Fahrrad nicht noch weiter zu vergießen, wollte aber hinzufügen
ist etwas, das Sie am Anfang eines Skripts hinzufügen können. Dieser Fehler tritt auf, wenn Variablen an keiner Stelle im Skript deklariert werden. Die Nachricht, die Sie sehen würden, ist
unbound variable
, aber wie andere erwähnen, wird keine leere Zeichenfolge oder kein Nullwert abgefangen. Um sicherzustellen, dass ein einzelner Wert nicht leer ist, können wir eine Variable testen, mit der sie erweitert wird${mystr:?}
, auch als Dollarzeichenerweiterung bezeichnet, was zu Fehlern führen würdeparameter null or not set
.quelle
Das Bash-Referenzhandbuch ist eine maßgebliche Informationsquelle zu Bash.
Hier ist ein Beispiel für das Testen einer Variablen, um festzustellen, ob sie vorhanden ist:
(Aus Abschnitt 6.3.2 .)
Beachten Sie, dass das Leerzeichen nach dem offenen
[
und bevor das]
ist nicht optional .Tipps für Vim-Benutzer
Ich hatte ein Skript mit mehreren Deklarationen wie folgt:
Aber ich wollte, dass sie sich auf bestehende Werte beschränken. Also habe ich sie neu geschrieben, um so auszusehen:
Ich konnte dies in vim mithilfe eines schnellen regulären Ausdrucks automatisieren:
Dies kann angewendet werden, indem die relevanten Zeilen visuell ausgewählt und dann eingegeben werden
:
. Die Befehlsleiste wird mit gefüllt:'<,'>
. Fügen Sie den obigen Befehl ein und drücken Sie die Eingabetaste.Getestet auf dieser Version von Vim:
Windows-Benutzer möchten möglicherweise unterschiedliche Zeilenenden.
quelle
Ich denke, dies ist eine viel klarere Möglichkeit, um zu überprüfen, ob eine Variable definiert ist:
Verwenden Sie es wie folgt:
quelle
grep
ist schrecklich. Beachten Sie, dassbash
Stützen${!var_name}
als Weg , um den Wert einer Variablen des Erhaltens , dessen Name in angegeben$var_name
, soname=value; value=1; echo ${name} ${!name}
Ausbeutenvalue 1
.Eine kürzere Version zum Testen undefinierter Variablen kann einfach sein:
quelle
call set ohne Argumente. Es gibt alle definierten Variablen aus.
Die letzten in der Liste sind die in Ihrem Skript definierten.
Sie können also die Ausgabe an etwas weiterleiten, das herausfinden kann, welche Dinge definiert sind und welche nicht
quelle