if test $# -gt 0; then printf 'arg <%s>\n' "$@"; fi.
Jens
210
Hinweis für Lösungssuchende: Es gibt viele hoch bewertete Antworten auf diese Frage, die die Frage "ist nicht leer" beantworten. Die mehr Korrekturlösungen ("is variable set") werden in den Antworten von Jens und Lionel unten erwähnt.
Nathan Kidd
8
Auch Russell Harmon und Seamus sind mit ihrem -vTest korrekt , obwohl dies anscheinend nur für neue Versionen von verfügbar ist bashund nicht über Shells hinweg tragbar ist.
... oder die falsche Antwort könnte von den anspruchsvolleren unter uns abgelehnt werden, da @prosseek das Problem nicht anspricht.
Dan3
Antworten:
2303
(Normalerweise) Der richtige Weg
if[-z ${var+x}];then echo "var is unset";else echo "var is set to '$var'";fi
Dabei ${var+x}handelt es sich um eine Parametererweiterung, die nichts varergibt, wenn sie nicht gesetzt ist, und die Zeichenfolge xansonsten ersetzt.
Zitate Exkurs
Anführungszeichen können weggelassen werden (so können wir ${var+x}stattdessen sagen "${var+x}"), da diese Syntax und Verwendung garantiert, dass dies nur zu etwas erweitert wird, für das keine Anführungszeichen erforderlich sind (da es entweder zu erweitert wird x(das keine Wortumbrüche enthält und daher keine Anführungszeichen benötigt) oder zu nichts (was dazu führt [ -z ], was bequemerweise den gleichen Wert (wahr) [ -z "" ]ergibt , der auch der Fall ist)).
Obwohl Anführungszeichen sicher weggelassen werden können und es nicht für alle sofort offensichtlich war (es war nicht einmal für den Erstautor dieser Anführungszeichenerklärung offensichtlich, der auch ein wichtiger Bash-Codierer ist), wäre es manchmal besser, die Lösung zu schreiben mit Anführungszeichen als [ -z "${var+x}" ], zu den sehr geringen möglichen Kosten einer O (1) -Geschwindigkeitsstrafe. Der Erstautor fügte dies auch als Kommentar neben dem Code hinzu, indem er diese Lösung verwendete und die URL zu dieser Antwort angab, die nun auch die Erklärung enthält, warum die Anführungszeichen sicher weggelassen werden können.
(Oft) Der falsche Weg
if[-z "$var"];then echo "var is blank";else echo "var is set to '$var'";fi
Dies ist häufig falsch, da nicht zwischen einer nicht gesetzten Variablen und einer auf die leere Zeichenfolge gesetzten Variablen unterschieden wird. Das heißt, wenn var='', dann gibt die obige Lösung "var is blank" aus.
Die Unterscheidung zwischen nicht gesetzt und "auf die leere Zeichenfolge setzen" ist in Situationen wichtig, in denen der Benutzer eine Erweiterung oder eine zusätzliche Liste von Eigenschaften angeben muss und diese nicht standardmäßig einen nicht leeren Wert angeben, während die Angabe der leeren Zeichenfolge dies tun sollte Lassen Sie das Skript eine leere Erweiterung oder Liste zusätzlicher Eigenschaften verwenden.
Die Unterscheidung ist jedoch möglicherweise nicht in jedem Szenario wesentlich. In diesen Fällen [ -z "$var" ]wird alles in Ordnung sein.
@ Garrett, Ihre Bearbeitung hat diese Antwort falsch gemacht, ${var+x}ist die richtige Substitution zu verwenden. Die Verwendung [ -z ${var:+x} ]erzeugt kein anderes Ergebnis als [ -z "$var" ].
Graeme
11
Das funktioniert nicht. Ich erhalte "nicht gesetzt", unabhängig davon, ob var auf einen Wert gesetzt ist oder nicht (gelöscht mit "unset var", "echo $ var" erzeugt keine Ausgabe).
Brent212
10
Für die Syntax der Lösung $ {parameter + word} lautet der offizielle Handbuchabschnitt gnu.org/software/bash/manual/… ; Ein Fehler darin ist jedoch, dass diese Syntax nicht sehr deutlich erwähnt wird, sondern nur ein Anführungszeichen angegeben wird (das Weglassen des Doppelpunkts [":"] führt zu einem Test nur für einen Parameter, der nicht gesetzt ist. $ {parameter: + word} [bedeutet] Wenn der Parameter null oder nicht gesetzt ist, wird nichts ersetzt, andernfalls wird die Erweiterung des Wortes ersetzt.); Die zitierte Referenz pubs.opengroup.org/onlinepubs/9699919799/utilities/… (gut zu wissen) enthält hier viel klarere Dokumente.
Destiny Architect
7
Es sieht aus wie Anführungszeichen sind erforderlich, wenn Sie mehrere Ausdrücke verwendet werden , zB [ -z "" -a -z ${var+x} ]wird bash: [: argument expectedin bash 4.3-ubuntu (aber nicht zB zsh). Ich mag die Antwort mit einer Syntax, die in einigen Fällen funktioniert, wirklich nicht.
FauxFaux
41
Die Verwendung eines einfachen [ -z $var ]ist nicht "falscher" als das Weglassen von Anführungszeichen. In beiden Fällen machen Sie Annahmen über Ihre Eingabe. Wenn Sie eine leere Zeichenfolge als nicht gesetzt behandeln möchten, [ -z $var ]ist dies alles, was Sie benötigen.
Nshew
909
Verwenden Sie diese Option, um nach Zeichenfolgenvariablen ungleich Null / ungleich Null zu suchen
if[-n "$1"]
Es ist das Gegenteil von -z. Ich benutze -nmehr als -z.
Sie würden es wie folgt verwenden:
if[-n "$1"];then
echo "You supplied the first parameter!"else
echo "First parameter not supplied."fi
Normalerweise ziehe ich es [[ ]]vor [ ], da [[ ]]es leistungsfähiger ist und in bestimmten Situationen weniger Probleme verursacht (siehe diese Frage für eine Erklärung des Unterschieds zwischen den beiden). Die Frage fragt speziell nach einer Bash- Lösung und erwähnt keine Portabilitätsanforderungen.
Flow
18
Die Frage ist, wie man sehen kann, ob eine Variable gesetzt ist . Dann nehme an, Sie können nicht , dass die Variable ist gesetzt.
HelloGoodbye
7
Ich stimme zu, []funktioniert besser, insbesondere für Shell-Skripte (ohne Bash).
Hengjie
73
Schlägt weiter set -u.
Ciro Santilli 法轮功 病毒 审查. 事件 法轮功
63
Beachten Sie, dass dies -nder Standardtest ist, also einfacher [ "$1" ]oder auch besser [[ $1 ]]. Beachten Sie auch, dass das [[ ]]Zitieren nicht erforderlich ist .
Der
478
So testen Sie, ob ein Parameter nicht gesetzt oder leer ("Null") oder mit einem Wert gesetzt ist :
+--------------------+----------------------+-----------------+-----------------+|Expression| parameter | parameter | parameter ||in script:|Set and NotNull|SetButNull|Unset|+--------------------+----------------------+-----------------+-----------------+| ${parameter:-word}| substitute parameter | substitute word | substitute word || ${parameter-word}| substitute parameter | substitute null | substitute word || ${parameter:=word}| substitute parameter | assign word | assign word || ${parameter=word}| substitute parameter | substitute null | assign word || ${parameter:?word}| substitute parameter | error, exit | error, exit || ${parameter?word}| substitute parameter | substitute null | error, exit || ${parameter:+word}| substitute word | substitute null | substitute null || ${parameter+word}| substitute word | substitute word | substitute null |+--------------------+----------------------+-----------------+-----------------+
In allen mit "Ersatz" angezeigten Fällen wird der Ausdruck durch den angezeigten Wert ersetzt. In allen mit "Zuweisen" angezeigten Fällen wird dem Parameter dieser Wert zugewiesen, der auch den Ausdruck ersetzt.
Um dies in Aktion zu zeigen:
+--------------------+----------------------+-----------------+-----------------+|Expression| FOO="world"| FOO=""| unset FOO ||in script:|(Set and NotNull)|(SetButNull)|(Unset)|+--------------------+----------------------+-----------------+-----------------+| ${FOO:-hello}| world | hello | hello || ${FOO-hello}| world |""| hello || ${FOO:=hello}| world | FOO=hello | FOO=hello || ${FOO=hello}| world |""| FOO=hello || ${FOO:?hello}| world | error, exit | error, exit || ${FOO?hello}| world |""| error, exit || ${FOO:+hello}| hello |""|""|| ${FOO+hello}| hello | hello |""|+--------------------+----------------------+-----------------+-----------------+
@HelloGoodbye Ja, es funktioniert: set foo; echo ${1:-set but null or unset}Echos "foo"; set --; echo ${1:-set but null or unset}Echos gesetzt, aber null ...
Jens
4
@HelloGoodbye Die Positionsparameter können eingestellt werden mit set:-)
Jens
95
Diese Antwort ist sehr verwirrend. Gibt es praktische Beispiele für die Verwendung dieser Tabelle?
Ben Davis
12
@BenDavis Die Details werden im Link zum POSIX-Standard erläutert, der auf das Kapitel verweist, aus dem die Tabelle stammt. Ein Konstrukt, das ich in fast jedem Skript verwende, das ich schreibe, besteht : ${FOOBAR:=/etc/foobar.conf}darin, einen Standardwert für eine Variable festzulegen, wenn diese nicht gesetzt oder null ist.
Jens
1
parameterist ein beliebiger Variablenname. wordist eine Zeichenfolge, die ersetzt werden muss, je nachdem, welche Syntax in der Tabelle Sie verwenden und ob die Variable $parametergesetzt, gesetzt, aber null oder nicht gesetzt ist. Nicht um die Dinge komplizierter zu machen, sondern wordkann auch Variablen enthalten! Dies kann sehr nützlich sein, um optionale Argumente zu übergeben, die durch ein Zeichen getrennt sind. Beispiel: ${parameter:+,${parameter}}Gibt ein Komma getrennt aus, ,$parameterwenn es gesetzt, aber nicht null ist. In diesem Fall wordist,${parameter}
TrinitronX
260
Während die meisten der hier angegebenen Techniken korrekt sind, unterstützt Bash 4.2 einen tatsächlichen Test auf das Vorhandensein einer Variablen ( Man Bash ), anstatt den Wert der Variablen zu testen.
Insbesondere verursacht dieser Ansatz keinen Fehler, wenn nach einer nicht gesetzten Variablen in gesucht wird set -uset -o nounset Gegensatz zu vielen anderen Ansätzen, wie z. B. der Verwendung, / mode[ -z .
In Bash 4.1.2, unabhängig davon, ob eine Variable gesetzt ist, [[ -v aaa ]]; echo $?==>-bash: conditional binary operator expected-bash: syntax error near 'aaa'
Dan
32
Das Argument '-v' zum eingebauten 'Test' wurde in Bash 4.2 hinzugefügt.
Ti Strga
19
Das Argument -v wurde als Ergänzung zur Shell-Option -u (Nomenmenge) hinzugefügt. Wenn 'nounset' aktiviert ist (set -u), gibt die Shell einen Fehler zurück und wird beendet, wenn sie nicht interaktiv ist. $ # war gut für die Überprüfung der Positionsparameter. Benannte Variablen mussten jedoch anders als mit Clobbering als nicht gesetzt identifiziert werden. Es ist bedauerlich, dass diese Funktion so spät verfügbar ist, da viele zwangsläufig mit früheren Versionen kompatibel sind. In diesem Fall können sie sie nicht verwenden. Die einzige andere Möglichkeit besteht darin, Tricks oder "Hacks" zu verwenden, um das Problem zu umgehen, wie oben gezeigt, aber es ist am unelegantesten.
Osirisgothra
2
Beachten Sie, dass dies nicht für Variablen funktioniert, die deklariert, aber nicht gesetzt sind. zBdeclare -a foo
miken32
17
Deshalb lese ich nach der akzeptierten / am höchsten bewerteten Antwort weiter.
Joe
176
Es gibt viele Möglichkeiten, dies zu tun, wobei die folgenden eine davon sind:
if[-z "$1"]
Dies ist erfolgreich, wenn $ 1 null oder nicht gesetzt ist
Es gibt einen Unterschied zwischen einem nicht gesetzten Parameter und einem Parameter mit einem Nullwert.
Chepper
21
Ich möchte nur pedantisch sein und darauf hinweisen, dass dies die entgegengesetzte Antwort auf die Frage ist. In den Fragen wird gefragt, ob die Variable gesetzt ist, nicht, ob die Variable nicht gesetzt ist.
Philluminati
47
[[ ]]ist nichts anderes als eine Portabilitätsfalle. if [ -n "$1" ]sollte hier verwendet werden.
Jens
73
Diese Antwort ist falsch. In der Frage wird nach einer Möglichkeit gefragt, festzustellen, ob eine Variable festgelegt ist und nicht, ob sie auf einen nicht leeren Wert festgelegt ist. Gegeben foo="", $foohat einen Wert, -zmeldet aber lediglich, dass er leer ist. Und -z $foowird explodieren, wenn Sie haben set -o nounset.
Keith Thompson
4
Dies hängt von der Definition von "Variable ist gesetzt" ab. Wenn Sie überprüfen möchten, ob die Variable auf eine Zeichenfolge ungleich Null festgelegt ist , ist die mbranning-Antwort korrekt. Wenn Sie jedoch überprüfen möchten, ob die Variable deklariert, aber nicht initialisiert ist (dh foo=), ist Russels Antwort korrekt.
Flow
77
Ich finde die POSIX-Tabelle in der anderen Antwort immer langsam, also hier meine Meinung dazu:
Beachten Sie, dass jede Gruppe (mit und ohne vorangestelltem Doppelpunkt) dieselben festgelegten und nicht festgelegten Fälle hat. Das einzige, was sich unterscheidet, ist die Behandlung der leeren Fälle.
Mit dem vorhergehenden Doppelpunkt sind die leeren und nicht gesetzten Fälle identisch, daher würde ich diese nach Möglichkeit verwenden (dh :=nicht nur =, weil der leere Fall inkonsistent ist).
Überschriften:
set means VARIABLEist nicht leer ( VARIABLE="something")
leer bedeutet VARIABLEleer / null ( VARIABLE="")
nicht gesetzte Mittel VARIABLEexistieren nicht ( unset VARIABLE)
Werte:
$VARIABLE bedeutet, dass das Ergebnis der ursprüngliche Wert der Variablen ist.
"default" bedeutet, dass das Ergebnis die bereitgestellte Ersatzzeichenfolge war.
"" bedeutet, dass das Ergebnis null ist (eine leere Zeichenfolge).
exit 127 bedeutet, dass das Skript mit dem Exit-Code 127 nicht mehr ausgeführt wird.
$(VARIABLE="default")bedeutet, dass das Ergebnis der ursprüngliche Wert der Variablen ist und die bereitgestellte Ersatzzeichenfolge der Variablen für die zukünftige Verwendung zugewiesen wird.
Sie haben nur diejenigen behoben, bei denen es sich um tatsächliche Codierungsfehler handelt (Fälle unerwünschter Indirektion bei der Arbeit mit Variablen). Ich habe eine Änderung vorgenommen, um einige weitere Fälle zu beheben, in denen der Dollar bei der Interpretation der Beschreibung einen Unterschied macht. Übrigens sind alle Shell-Variablen (mit Ausnahme von Arrays) String-Variablen. Es kann einfach vorkommen, dass sie eine Zeichenfolge enthalten, die als Zahl interpretiert werden kann. Wenn Sie über Zeichenfolgen sprechen, wird die Nachricht nur beschlagen. Anführungszeichen haben nichts mit Zeichenfolgen zu tun, sie sind nur eine Alternative zum Entkommen. VARIABLE=""könnte geschrieben werden als VARIABLE=. Ersteres ist jedoch besser lesbar.
Palec
Vielen Dank für die Tabelle, es ist sehr nützlich, aber ich versuche, das Skript zu beenden, wenn es nicht gesetzt oder leer ist. Aber der Exit-Code, den ich bekomme, ist 1, nicht 127.
Astronaut
64
Um zu sehen, ob eine Variable nicht leer ist, verwende ich
if[[ $var ]];then...# `$var' expands to a nonempty string
Das Gegenteil testet, ob eine Variable entweder nicht gesetzt oder leer ist:
if[[! $var ]];then...# `$var' expands to the empty string (set or not)
Um zu sehen, ob eine Variable gesetzt ist (leer oder nicht leer), verwende ich
if[[ ${var+x}]];then...# `var' exists (empty or nonempty)if[[ ${1+x}]];then...# Parameter 1 exists (empty or nonempty)
Das Gegenteil testet, ob eine Variable nicht gesetzt ist:
if[[! ${var+x}]];then...# `var' is not set at allif[[! ${1+x}]];then...# We were called with no arguments
Ich benutze das auch schon eine Weile; nur in reduzierter Weise:[ $isMac ] && param="--enable-shared"
@ Bhaskar Ich denke, das liegt daran, dass diese Antwort bereits fast ein halbes Jahr zuvor im Wesentlichen dieselbe Antwort lieferte (verwenden Sie ${variable+x}, um xiff zu erhalten $variable). Außerdem enthält es viel detailliertere Erklärungen, warum es richtig ist.
Mark Haferkamp
aber ${variable+x}ist weniger lesbar (& offensichtlich)
knocte
35
Bei einer modernen Version von Bash (4.2 oder höher, glaube ich; ich weiß es nicht genau) würde ich Folgendes versuchen:
if[!-v SOMEVARIABLE ]#note the lack of a $ sigilthen
echo "Variable is unset"elif[-z "$SOMEVARIABLE"]then
echo "Variable is set to an empty string"else
echo "Variable is set to some string"fi
Beachten Sie auch, dass dies [ -v "$VARNAME" ]nicht falsch ist, sondern einfach einen anderen Test durchführt. Nehmen wir an VARNAME=foo; Dann wird geprüft, ob eine Variable mit dem Namen foogesetzt ist.
Chepper
5
Hinweis für diejenigen, die Portabilität -v
wünschen
Wenn man bekommt [: -v: unexpected operator, muss man sicherstellen, bashstatt zu verwenden sh.
Koppor
25
if["$1"!=""];then
echo \$1 is setelse
echo \$1 is not setfi
Obwohl es für Argumente normalerweise am besten ist, $ # zu testen, was meiner Meinung nach die Anzahl der Argumente ist.
if[ $# -gt 0 ]; then
echo \$1 is setelse
echo \$1 is not setfi
Der erste Test ist rückwärts; Ich denke du willst [ "$1" != "" ](oder [ -n "$1" ]) ...
Gordon Davisson
10
Dies schlägt fehl, wenn $1die leere Zeichenfolge festgelegt ist.
Hallo Goodbye
2
Der zweite Teil der Antwort (Zählparameter) ist eine nützliche Problemumgehung für den ersten Teil der Antwort, der nicht funktioniert, wenn $1eine leere Zeichenfolge festgelegt ist.
Mark Berry
Dies schlägt fehl, wenn set -o nounsetes aktiviert ist.
Flimm
21
Hinweis
Ich gebe aufgrund des bashTags eine stark auf Bash ausgerichtete Antwort .
Kurze Antwort
Solange Sie nur mit benannten Variablen in Bash arbeiten, sollte diese Funktion Ihnen immer mitteilen, ob die Variable festgelegt wurde, auch wenn es sich um ein leeres Array handelt.
variable-is-set(){
declare -p "$1"&>/dev/null
}
Warum das so ist
Wenn vares sich bei Bash (mindestens bis 3.0) um eine deklarierte / gesetzte Variable handelt, wird declare -p varein declareBefehl ausgegeben , der die Variable varauf den aktuellen Typ und Wert setzt und den Statuscode 0(Erfolg) zurückgibt . Wenn varnicht deklariert ist, wird declare -p vareine Fehlermeldung an den stderrStatuscode ausgegeben und dieser zurückgegeben 1. Leitet mit &>/dev/nullund leitet sowohl regulär stdoutals auch stderrAusgabe an um/dev/null , wird nie gesehen und ohne den Statuscode zu ändern. Somit gibt die Funktion nur den Statuscode zurück.
Warum andere Methoden (manchmal) in Bash fehlschlagen
[ -n "$var" ]: Dies prüft nur, ob ${var[0]}es nicht leer ist. (In Bash $varist das gleiche wie ${var[0]}.)
[ -n "${var+x}" ]: Dies prüft nur, ob ${var[0]}gesetzt ist.
[ "${#var[@]}" != 0 ]: Dies prüft nur, ob mindestens ein Index von $vargesetzt ist.
Wenn diese Methode in Bash fehlschlägt
Dies funktioniert nur bei benannten Variablen (einschließlich $_), nicht bestimmten Sondergrößen ( $!, $@, $#, $$, $*, $?, $-, $0, $1, $2, ... und alle , die ich vergessen habe). Da es sich bei keinem dieser Arrays um Arrays handelt, [ -n "${var+x}" ]funktioniert der POSIX-Stil für alle diese speziellen Variablen. Achten Sie jedoch darauf, dass Sie es nicht in eine Funktion einschließen, da viele spezielle Variablen beim Aufrufen von Funktionen Werte / Existenz ändern.
Hinweis zur Shell-Kompatibilität
Wenn Ihr Skript Arrays enthält und Sie versuchen, es mit so vielen Shells wie möglich kompatibel zu machen, sollten Sie die Verwendung von typeset -panstelle von in Betracht ziehen declare -p. Ich habe gelesen, dass ksh nur das erstere unterstützt, konnte dies aber nicht testen. Ich weiß, dass Bash 3.0+ und Zsh 5.5.1 beide unterstützen typeset -pund declare -psich nur dadurch unterscheiden, dass eines eine Alternative für das andere ist. Aber ich habe keine Unterschiede über diese beiden Schlüsselwörter hinaus getestet, und ich habe keine anderen Shells getestet.
Wenn Ihr Skript POSIX sh-kompatibel sein soll, können Sie keine Arrays verwenden. Ohne Arrays [ -n "{$var+x}" ]funktioniert.
Vergleichscode für verschiedene Methoden in Bash
Diese Funktion deaktiviert die Variable var, evals den übergebenen Code, führt Tests aus, um festzustellen, ob varder evald-Code festgelegt ist, und zeigt schließlich die resultierenden Statuscodes für die verschiedenen Tests an.
Ich Skipping test -v var, [ -v var ]und [[ -v var ]]weil sie identische Ergebnisse an den POSIX - Standard ergeben [ -n "${var+x}" ], während erfordern Bash 4.2+. Ich überspringe auch, typeset -pweil es das gleiche ist wie declare -pin den Shells, die ich getestet habe (Bash 3.0 bis 5.0 und Zsh 5.5.1).
is-var-set-after(){# Set var by passed expression.
unset var
eval"$1"# Run the tests, in increasing order of accuracy.[-n "$var"]# (index 0 of) var is nonempty
nonempty=$?[-n "${var+x}"]# (index 0 of) var is set, maybe empty
plus=$?["${#var[@]}"!=0]# var has at least one index set, maybe empty
count=$?
declare -p var &>/dev/null # var has been declared (any type)
declared=$?# Show test results.
printf '%30s: %2s %2s %2s %2s\n'"$1" $nonempty $plus $count $declared
}
Testfallcode
Beachten Sie, dass Testergebnisse unerwartet sein können, da Bash nicht numerische Array-Indizes als "0" behandelt, wenn die Variable nicht als assoziatives Array deklariert wurde. Außerdem sind assoziative Arrays nur in Bash 4.0+ gültig.
# Header.
printf '%30s: %2s %2s %2s %2s\n'"test"'-n''+x''#@''-p'# First 5 tests: Equivalent to setting 'var=foo' because index 0 of an# indexed array is also the nonindexed value, and non-numerical# indices in an array not declared as associative are the same as# index 0.
is-var-set-after "var=foo"# 0 0 0 0
is-var-set-after "var=(foo)"# 0 0 0 0
is-var-set-after "var=([0]=foo)"# 0 0 0 0
is-var-set-after "var=([x]=foo)"# 0 0 0 0
is-var-set-after "var=([y]=bar [x]=foo)"# 0 0 0 0# '[ -n "$var" ]' fails when var is empty.
is-var-set-after "var=''"# 1 0 0 0
is-var-set-after "var=([0]='')"# 1 0 0 0# Indices other than 0 are not detected by '[ -n "$var" ]' or by# '[ -n "${var+x}" ]'.
is-var-set-after "var=([1]='')"# 1 1 0 0
is-var-set-after "var=([1]=foo)"# 1 1 0 0
is-var-set-after "declare -A var; var=([x]=foo)"# 1 1 0 0# Empty arrays are only detected by 'declare -p'.
is-var-set-after "var=()"# 1 1 1 0
is-var-set-after "declare -a var"# 1 1 1 0
is-var-set-after "declare -A var"# 1 1 1 0# If 'var' is unset, then it even fails the 'declare -p var' test.
is-var-set-after "unset var"# 1 1 1 1
Testausgabe
Die Test Mnemonik in der Kopfzeile entsprechen [ -n "$var" ], [ -n "${var+x}" ], [ "${#var[@]}" != 0 ], und declare -p varist.
declare -p var &>/dev/null ist (100%?) zuverlässig für das Testen benannter Variablen in Bash seit mindestens 3.0.
[ -n "${var+x}" ] ist in POSIX-kompatiblen Situationen zuverlässig, kann jedoch keine Arrays verarbeiten.
Es gibt andere Tests zum Überprüfen, ob eine Variable nicht leer ist, und zum Überprüfen auf deklarierte Variablen in anderen Shells. Diese Tests eignen sich jedoch weder für Bash- noch für POSIX-Skripte.
Von den Antworten, die ich versucht habe, ist diese ( declare -p var &>/dev/null) die EINZIGE, die funktioniert. VIELEN DANK!
user1387866
2
@ mark-haferkamp Ich habe versucht, Ihre Antwort zu bearbeiten, um das kritische vorangestellte "/" zu Ihrem Funktionscode hinzuzufügen, damit er lautet, ... &> /dev/nullaber SO würde mich nicht ein einzelnes Zeichen bearbeiten lassen 🙄 (muss> 6 Zeichen sein - habe sogar versucht, Leerzeichen hinzuzufügen aber es hat nicht funktioniert). Es könnte sich auch lohnen, die Funktion zu ändern, um $1für ein Beispiel mit dem Namen Variable (z. B. OUTPUT_DIR) auszuschalten, da, wie Sie bereits betont haben, spezielle Variablen wie $1hier nicht funktionieren. Auf jeden Fall ist es eine kritische Änderung, andernfalls versucht der Code, eine Datei zu erstellen, die nullin einem relativen Verzeichnis namens aufgerufen wird dev. Übrigens - tolle Antwort!
Joehanna
Die Verwendung des Namens der Variablen ohne das Präfix $ funktioniert ebenfalls: Gibt declare -p PATH &> /dev/null0 declare -p ASDFASDGFASKDF &> /dev/nullzurück, wobei 1 zurückgegeben wird (bei Bash 5.0.11 (1) -Veröffentlichung)
Joehanna
1
Gute Arbeit! 1 Wort der Vorsicht: declare vardeklariert var als Variable, setzt es aber nicht in Bezug auf set -o nounset: Test mitdeclare foo bar=; set -o nounset; echo $bar; echo $foo
xebeche
@joehanna Danke, dass du das Vermisste erwischt hast /! Ich habe das behoben, aber ich denke, die Logik ist verwirrend genug, um eine Funktion zu rechtfertigen, insbesondere angesichts des Kommentars von @ xebeche. @xebeche Das ist unpraktisch für meine Antwort.… Es sieht so aus, als müsste ich etwas wie declare -p "$1" | grep =oder ausprobieren test -v "$1".
Mark Haferkamp
19
Für diejenigen , die für ungesetzt zu überprüfen suchen oder leeren , wenn sie in einem Skript mit set -u:
if[-z "${var-}"];then
echo "Must provide var environment variable. Exiting...."
exit 1fi
Die reguläre [ -z "$var" ]Prüfung schlägt mit var; unbound variableif fehl, wird set -ujedoch zu einer leeren Zeichenfolge [ -z "${var-}" ]erweitert , wenn sie varnicht fehlgeschlagen ist.
Ihnen fehlt ein Doppelpunkt. Es sollte ${var:-}nicht sein ${var-}. Aber in Bash kann ich bestätigen, dass es auch ohne Doppelpunkt funktioniert.
Palec
3
${var:-}und ${var-}verschiedene Dinge bedeuten. ${var:-}wird auf leere Zeichenfolge erweitert, wenn varnicht gesetzt oder null, und ${var-}wird nur dann auf leere Zeichenfolge erweitert, wenn nicht gesetzt.
RubenLaguna
Ich habe gerade etwas Neues gelernt, danke! Das Weglassen des Doppelpunkts führt zu einem Test nur für einen Parameter, der nicht festgelegt ist. 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. Hier macht es keinen Unterschied, aber gut zu wissen.
Palec
17
Sie möchten beenden, wenn es nicht gesetzt ist
Das hat bei mir funktioniert. Ich wollte, dass mein Skript mit einer Fehlermeldung beendet wird, wenn kein Parameter festgelegt wurde.
#!/usr/bin/env bashset-o errexit
# Get the value and empty validation check all in one
VER="${1:?You must pass a version of the format 0.0.0 as the only argument}"
Dies wird mit einem Fehler zurückgegeben, wenn es ausgeführt wird
peek@peek:~$ ./setver.sh
./setver.sh: line 13:1:You must pass a version of the format 0.0.0 as the only argument
Nur prüfen, kein Beenden - Leer und Nicht gesetzt sind UNGÜLTIG
Versuchen Sie diese Option, wenn Sie nur überprüfen möchten, ob der Wert set = VALID oder unset / empty = INVALID ist.
Und das ist die Antwort auf die Frage. Verwenden Sie diese Option, wenn Sie nur überprüfen möchten, ob der Wert set / empty = VALID oder unset = INVALID ist.
HINWEIS, die "1" in "..- 1}" ist unbedeutend, es kann alles sein (wie x)
Verwenden Sie [ -n "$x" ], wie andere bereits angegeben haben , um zu überprüfen, ob eine Variable mit einem nicht leeren Wert festgelegt ist .
In den meisten Fällen empfiehlt es sich, eine Variable mit einem leeren Wert genauso zu behandeln wie eine nicht gesetzte Variable. Sie können die beiden jedoch unterscheiden, wenn Sie Folgendes benötigen: [ -n "${x+set}" ]( "${x+set}"Erweitert auf setif xist gesetzt und auf die leere Zeichenfolge, wenn nicht gesetzt xist).
Um zu überprüfen, ob ein Parameter übergeben wurde, testen Sie $#die Anzahl der Parameter, die an die Funktion (oder an das Skript, wenn sie nicht in einer Funktion enthalten sind) übergeben wurden (siehe Pauls Antwort ).
Lesen Sie den Abschnitt "Parametererweiterung" auf der bashManpage. Die Parametererweiterung bietet keinen allgemeinen Test für eine zu setzende Variable, aber es gibt verschiedene Möglichkeiten, einen Parameter zu bearbeiten, wenn er nicht gesetzt ist.
Zum Beispiel:
function a {
first_arg=${1-foo}# rest of the function}
wird first_arggleich gesetzt, $1wenn es zugewiesen ist, andernfalls wird der Wert "foo" verwendet. Wenn aunbedingt ein einzelner Parameter verwendet werden muss und kein guter Standardwert vorhanden ist, können Sie mit einer Fehlermeldung beenden, wenn kein Parameter angegeben wird:
function a {: ${1?a must take a single argument}# rest of the function}
(Beachten Sie die Verwendung von :als Null-Befehl, der nur die Werte seiner Argumente erweitert. $1In diesem Beispiel möchten wir nichts damit anfangen. Beenden Sie einfach, wenn er nicht festgelegt ist.)
Die Verwendung [[ -z "$var" ]]ist der einfachste Weg, um festzustellen, ob eine Variable festgelegt wurde oder nicht. -zDiese Option unterscheidet jedoch nicht zwischen einer nicht gesetzten Variablen und einer Variablen, die auf eine leere Zeichenfolge festgelegt ist:
$#: gibt Ihnen die Anzahl der Positionsparameter an.
declare -p: gibt Ihnen die Definition der als Parameter übergebenen Variablen. Wenn vorhanden, wird 0 zurückgegeben. Wenn nicht, wird 1 zurückgegeben und eine Fehlermeldung ausgegeben.
&> /dev/null: Unterdrückt die Ausgabe von, declare -pohne den Rückkehrcode zu beeinflussen.
Die obigen Antworten funktionieren nicht, wenn die Bash-Option set -uaktiviert ist. Sie sind auch nicht dynamisch, z. B. wie wird getestet, ob eine Variable mit dem Namen "Dummy" definiert ist? Versuche dies:
is_var_defined(){if[ $# -ne 1 ]then
echo "Expected exactly one argument: variable name as string, e.g., 'my_var'"
exit 1fi# Tricky. Since Bash option 'set -u' may be enabled, we cannot directly test if a variable# is defined with this construct: [ ! -z "$var" ]. Instead, we must use default value# substitution with this construct: [ ! -z "${var:-}" ]. Normally, a default value follows the# operator ':-', but here we leave it blank for empty (null) string. Finally, we need to# substitute the text from $1 as 'var'. This is not allowed directly in Bash with this# construct: [ ! -z "${$1:-}" ]. We need to use indirection with eval operator.# Example: $1="var"# Expansion for eval operator: "[ ! -z \${$1:-} ]" -> "[ ! -z \${var:-} ]"# Code execute: [ ! -z ${var:-} ]eval"[ ! -z \${$1:-} ]"return $?# Pedantic.}
Sie brauchen Zitate um $1, dh , [ ! -z "$1" ]. Oder Sie können [[ ! -z $1 ]]in bash / ksh / zsh schreiben .
Gilles 'SO - hör auf böse zu sein'
5
Dies schlägt fehl, wenn $1die leere Zeichenfolge festgelegt ist.
Hallo Goodbye
4
Mein bevorzugter Weg ist folgender:
$ var=10
$ if! ${var+false};then echo "is set";else echo "NOT set";fi
is set
$ unset -v var
$ if! ${var+false};then echo "is set";else echo "NOT set";fi
NOT set
Wenn also eine Variable gesetzt ist, wird sie im Grunde genommen "eine Negation des Ergebnisses false" (was sein wird true= "wird gesetzt").
Und wenn es nicht gesetzt ist, wird es "eine Negation des Ergebnisses true" (wie das leere Ergebnis ergibt true) (endet also als false= "NICHT gesetzt").
In einer Shell können Sie den -zOperator True verwenden, wenn die Länge der Zeichenfolge Null ist.
Ein einfacher Einzeiler zum Festlegen der Standardeinstellung, MY_VARwenn diese nicht festgelegt ist. Andernfalls können Sie optional die folgende Meldung anzeigen:
if[[ ${1:+isset}]]then echo "It was set and not null.">&2else echo "It was not set or it was null.">&2fiif[[ ${1+isset}]]then echo "It was set but might be null.">&2else echo "It was was not set.">&2fi
$1, $2Und bis zu $Nist immer gesetzt. Entschuldigung, das ist fehlgeschlagen.
Ich habe es versucht und es hat nicht funktioniert, vielleicht wird meine Bash-Version dafür nicht unterstützt. Idk, tut mir leid, wenn ich falsch liege. :)
0
Ich habe einen (viel) besseren Code gefunden, um dies zu tun, wenn Sie nach etwas suchen möchten $@.
if [[$ 1 = ""]]
dann
Echo '$ 1 ist leer'
sonst
Echo '$ 1 ist voll'
fi
Warum das alles? Alles in $@ist in Bash vorhanden, aber standardmäßig ist es leer test -zund test -nkann Ihnen nicht helfen.
Update: Sie können auch die Anzahl der Zeichen in einem Parameter zählen.
if [$ {# 1} = 0]
dann
Echo '$ 1 ist leer'
sonst
Echo '$ 1 ist voll'
fi
Willkommen bei StackOverflow. Während Ihre Antwort geschätzt wird, ist es am besten, mehr als nur Code zu geben. Könnten Sie Ihrer Antwort eine Begründung oder eine kleine Erklärung hinzufügen? Auf dieser Seite finden Sie weitere Ideen zur Erweiterung Ihrer Antwort.
Celeo
0
Das benutze ich jeden Tag:
## Check if a variable is set# param1 name of the variable#function is_set(){[[-n "${1}"]]&& test -n "$(eval "echo "\${${1}+x}"")"}
Dies funktioniert gut unter Linux und Solaris bis Bash 3.0.
Seit Bash 2.0+ ist eine indirekte Erweiterung verfügbar. Sie könnten die lange und komplexe (mit einer auch enthaltenen test -n "$(eval "echo "\${${1}+x}"")"[[ ${!1+x} ]]
0
Ich mag Hilfsfunktionen, um die groben Details von Bash zu verbergen. In diesem Fall wird dadurch noch mehr (versteckte) Grobheit hinzugefügt:
# The first ! negates the result (can't use -n to achieve this)# the second ! expands the content of varname (can't do ${$varname})functionIsDeclared_Tricky{local varname="$1"![-z ${!varname+x}]}
Da ich zum ersten Mal Fehler in dieser Implementierung hatte (inspiriert von den Antworten von Jens und Lionel), habe ich eine andere Lösung gefunden:
# Ask for the properties of the variable - fails if not declaredfunctionIsDeclared(){
declare -p $1 &>/dev/null
}
Ich finde es direkter, schüchterner und leichter zu verstehen / zu merken. Testfall zeigt, dass es äquivalent ist:
function main(){
declare -i xyz
local foo
local bar=local baz=''IsDeclared_Tricky xyz; echo "IsDeclared_Tricky xyz: $?"IsDeclared_Tricky foo; echo "IsDeclared_Tricky foo: $?"IsDeclared_Tricky bar; echo "IsDeclared_Tricky bar: $?"IsDeclared_Tricky baz; echo "IsDeclared_Tricky baz: $?"IsDeclared xyz; echo "IsDeclared xyz: $?"IsDeclared foo; echo "IsDeclared foo: $?"IsDeclared bar; echo "IsDeclared bar: $?"IsDeclared baz; echo "IsDeclared baz: $?"}
main
Der Testfall auch zeigt , dass local varsich NICHT var erklären (es sei denn , durch ‚=‘ folgt). Seit einiger Zeit dachte ich, ich hätte Variablen auf diese Weise deklariert, nur um jetzt herauszufinden, dass ich nur meine Absicht ausgedrückt habe ... Es ist ein No-Op, denke ich.
Ich benutze diesen Test meistens, um Funktionen auf eine etwas "elegante" und sichere Weise (fast wie eine Schnittstelle ...) mit Parametern zu versehen (und zurückzugeben ):
#auxiliary functionsfunction die(){
echo "Error: $1"; exit 1}function assertVariableDeclared(){IsDeclared"$1"|| die "variable not declared: $1"}function expectVariables(){while(( $# > 0 )); do
assertVariableDeclared $1; shift
done}# actual examplefunction exampleFunction(){
expectVariables inputStr outputStr
outputStr="$inputStr world!"}function bonus(){local inputStr='Hello'local outputStr=# remove this to trigger error
exampleFunction
echo $outputStr
}
bonus
Wenn mit all aufgerufen, müssen Variablen deklariert werden:
Nachdem Sie alle Antworten überflogen haben, funktioniert dies auch:
if[[-z $SOME_VAR ]];then read -p "Enter a value for SOME_VAR: " SOME_VAR;fi
echo "SOME_VAR=$SOME_VAR"
Wenn Sie nicht SOME_VARanstelle von dem setzen, was ich habe $SOME_VAR, wird es auf einen leeren Wert gesetzt. $ist notwendig, damit dies funktioniert.
wird nicht funktionieren, wenn Sie set -uin der Tat haben, die den unboud variableFehler drucken wird
Michael Heuberger
0
Zusammenfassung
Verwenden Sie test -n "${var-}"diese Option , um zu überprüfen, ob die Variable nicht leer ist (und daher auch definiert / gesetzt werden muss).
Verwenden Sie test ! -z "${var+}"diese Option , um zu überprüfen, ob die Variable definiert / festgelegt ist (auch wenn sie leer ist).
Beachten Sie, dass der erste Anwendungsfall in Shell-Skripten viel häufiger vorkommt und dass Sie diesen normalerweise verwenden möchten.
Anmerkungen
Diese Lösung sollte in allen POSIX-Shells (sh, bash, zsh, ksh, dash) funktionieren.
Einige der anderen Antworten auf diese Frage sind korrekt, können jedoch für Personen, die noch keine Erfahrung mit Shell-Skripten haben, verwirrend sein. Daher wollte ich eine TLDR-Antwort bereitstellen, die für solche Personen am wenigsten verwirrend ist.
Erläuterung
Um zu verstehen, wie diese Lösung funktioniert, müssen Sie den POSIX- testBefehl und die Erweiterung der POSIX-Shell-Parameter ( Spezifikation ) verstehen. Lassen Sie uns also die absoluten Grundlagen behandeln, die zum Verständnis der Antwort erforderlich sind.
Der Testbefehl wertet einen Ausdruck aus und gibt true oder false zurück (über seinen Exit-Status). Der Operator -ngibt true zurück, wenn der Operand eine nicht leere Zeichenfolge ist. Gibt beispielsweise test -n "a"true zurück, während test -n ""false zurückgegeben wird. Um zu überprüfen, ob eine Variable nicht leer ist (was bedeutet, dass sie definiert werden muss), können Sie sie verwenden test -n "$var". Einige Shell-Skripte verfügen jedoch über eine Option set ( set -u), die bewirkt, dass Verweise auf undefinierte Variablen einen Fehler ausgeben. Wenn die Variable varnicht definiert ist, verursacht der Ausdruck $aeinen Fehler. Um diesen Fall korrekt zu behandeln, müssen Sie die Variablenerweiterung verwenden, die die Shell anweist, die Variable durch eine alternative Zeichenfolge zu ersetzen, wenn sie nicht definiert ist, um den oben genannten Fehler zu vermeiden.
Die Variablenerweiterung ${var-}bedeutet: Wenn die Variable varundefiniert ist (auch als "nicht gesetzt" bezeichnet), ersetzen Sie sie durch eine leere Zeichenfolge. Gibt also test -n "${var-}"true zurück, wenn $vares nicht leer ist. Dies ist fast immer das, was Sie in Shell-Skripten einchecken möchten. Die umgekehrte Prüfung, ob $varundefiniert oder nicht leer, wäre test -z "${var-}".
Nun zum zweiten Anwendungsfall: Überprüfen, ob die Variable vardefiniert ist, ob leer oder nicht. Dies ist ein weniger verbreiteter und etwas komplexer Anwendungsfall, und ich würde Ihnen raten, die großartige Antwort von Lionels zu lesen , um sie besser zu verstehen.
Ich denke du meinst set -o nounsetnicht set -o noun set. Dies funktioniert nur für Variablen, die exportbearbeitet wurden. Außerdem werden Ihre Einstellungen so geändert, dass das Rückgängigmachen umständlich ist.
if test $# -gt 0; then printf 'arg <%s>\n' "$@"; fi
.-v
Test korrekt , obwohl dies anscheinend nur für neue Versionen von verfügbar istbash
und nicht über Shells hinweg tragbar ist.Antworten:
(Normalerweise) Der richtige Weg
Dabei
${var+x}
handelt es sich um eine Parametererweiterung, die nichtsvar
ergibt, wenn sie nicht gesetzt ist, und die Zeichenfolgex
ansonsten ersetzt.Zitate Exkurs
Anführungszeichen können weggelassen werden (so können wir
${var+x}
stattdessen sagen"${var+x}"
), da diese Syntax und Verwendung garantiert, dass dies nur zu etwas erweitert wird, für das keine Anführungszeichen erforderlich sind (da es entweder zu erweitert wirdx
(das keine Wortumbrüche enthält und daher keine Anführungszeichen benötigt) oder zu nichts (was dazu führt[ -z ]
, was bequemerweise den gleichen Wert (wahr)[ -z "" ]
ergibt , der auch der Fall ist)).Obwohl Anführungszeichen sicher weggelassen werden können und es nicht für alle sofort offensichtlich war (es war nicht einmal für den Erstautor dieser Anführungszeichenerklärung offensichtlich, der auch ein wichtiger Bash-Codierer ist), wäre es manchmal besser, die Lösung zu schreiben mit Anführungszeichen als
[ -z "${var+x}" ]
, zu den sehr geringen möglichen Kosten einer O (1) -Geschwindigkeitsstrafe. Der Erstautor fügte dies auch als Kommentar neben dem Code hinzu, indem er diese Lösung verwendete und die URL zu dieser Antwort angab, die nun auch die Erklärung enthält, warum die Anführungszeichen sicher weggelassen werden können.(Oft) Der falsche Weg
Dies ist häufig falsch, da nicht zwischen einer nicht gesetzten Variablen und einer auf die leere Zeichenfolge gesetzten Variablen unterschieden wird. Das heißt, wenn
var=''
, dann gibt die obige Lösung "var is blank" aus.Die Unterscheidung zwischen nicht gesetzt und "auf die leere Zeichenfolge setzen" ist in Situationen wichtig, in denen der Benutzer eine Erweiterung oder eine zusätzliche Liste von Eigenschaften angeben muss und diese nicht standardmäßig einen nicht leeren Wert angeben, während die Angabe der leeren Zeichenfolge dies tun sollte Lassen Sie das Skript eine leere Erweiterung oder Liste zusätzlicher Eigenschaften verwenden.
Die Unterscheidung ist jedoch möglicherweise nicht in jedem Szenario wesentlich. In diesen Fällen
[ -z "$var" ]
wird alles in Ordnung sein.quelle
${var+x}
ist die richtige Substitution zu verwenden. Die Verwendung[ -z ${var:+x} ]
erzeugt kein anderes Ergebnis als[ -z "$var" ]
.[ -z "" -a -z ${var+x} ]
wirdbash: [: argument expected
in bash 4.3-ubuntu (aber nicht zB zsh). Ich mag die Antwort mit einer Syntax, die in einigen Fällen funktioniert, wirklich nicht.[ -z $var ]
ist nicht "falscher" als das Weglassen von Anführungszeichen. In beiden Fällen machen Sie Annahmen über Ihre Eingabe. Wenn Sie eine leere Zeichenfolge als nicht gesetzt behandeln möchten,[ -z $var ]
ist dies alles, was Sie benötigen.Verwenden Sie diese Option, um nach Zeichenfolgenvariablen ungleich Null / ungleich Null zu suchen
Es ist das Gegenteil von
-z
. Ich benutze-n
mehr als-z
.Sie würden es wie folgt verwenden:
quelle
[[ ]]
vor[ ]
, da[[ ]]
es leistungsfähiger ist und in bestimmten Situationen weniger Probleme verursacht (siehe diese Frage für eine Erklärung des Unterschieds zwischen den beiden). Die Frage fragt speziell nach einer Bash- Lösung und erwähnt keine Portabilitätsanforderungen.[]
funktioniert besser, insbesondere für Shell-Skripte (ohne Bash).set -u
.-n
der Standardtest ist, also einfacher[ "$1" ]
oder auch besser[[ $1 ]]
. Beachten Sie auch, dass das[[ ]]
Zitieren nicht erforderlich ist .So testen Sie, ob ein Parameter nicht gesetzt oder leer ("Null") oder mit einem Wert gesetzt ist :
Quelle: POSIX: Parametererweiterung :
Um dies in Aktion zu zeigen:
quelle
set foo; echo ${1:-set but null or unset}
Echos "foo";set --; echo ${1:-set but null or unset}
Echos gesetzt, aber null ...set
:-): ${FOOBAR:=/etc/foobar.conf}
darin, einen Standardwert für eine Variable festzulegen, wenn diese nicht gesetzt oder null ist.parameter
ist ein beliebiger Variablenname.word
ist eine Zeichenfolge, die ersetzt werden muss, je nachdem, welche Syntax in der Tabelle Sie verwenden und ob die Variable$parameter
gesetzt, gesetzt, aber null oder nicht gesetzt ist. Nicht um die Dinge komplizierter zu machen, sondernword
kann auch Variablen enthalten! Dies kann sehr nützlich sein, um optionale Argumente zu übergeben, die durch ein Zeichen getrennt sind. Beispiel:${parameter:+,${parameter}}
Gibt ein Komma getrennt aus,,$parameter
wenn es gesetzt, aber nicht null ist. In diesem Fallword
ist,${parameter}
Während die meisten der hier angegebenen Techniken korrekt sind, unterstützt Bash 4.2 einen tatsächlichen Test auf das Vorhandensein einer Variablen ( Man Bash ), anstatt den Wert der Variablen zu testen.
Insbesondere verursacht dieser Ansatz keinen Fehler, wenn nach einer nicht gesetzten Variablen in gesucht wird
set -u
set -o nounset
Gegensatz zu vielen anderen Ansätzen, wie z. B. der Verwendung, / mode[ -z
.quelle
[[ -v aaa ]]; echo $?
==>-bash: conditional binary operator expected
-bash: syntax error near 'aaa'
declare -a foo
Es gibt viele Möglichkeiten, dies zu tun, wobei die folgenden eine davon sind:
Dies ist erfolgreich, wenn $ 1 null oder nicht gesetzt ist
quelle
[[ ]]
ist nichts anderes als eine Portabilitätsfalle.if [ -n "$1" ]
sollte hier verwendet werden.foo=""
,$foo
hat einen Wert,-z
meldet aber lediglich, dass er leer ist. Und-z $foo
wird explodieren, wenn Sie habenset -o nounset
.foo=
), ist Russels Antwort korrekt.Ich finde die POSIX-Tabelle in der anderen Antwort immer langsam, also hier meine Meinung dazu:
Beachten Sie, dass jede Gruppe (mit und ohne vorangestelltem Doppelpunkt) dieselben festgelegten und nicht festgelegten Fälle hat. Das einzige, was sich unterscheidet, ist die Behandlung der leeren Fälle.
Mit dem vorhergehenden Doppelpunkt sind die leeren und nicht gesetzten Fälle identisch, daher würde ich diese nach Möglichkeit verwenden (dh
:=
nicht nur=
, weil der leere Fall inkonsistent ist).Überschriften:
VARIABLE
ist nicht leer (VARIABLE="something"
)VARIABLE
leer / null (VARIABLE=""
)VARIABLE
existieren nicht (unset VARIABLE
)Werte:
$VARIABLE
bedeutet, dass das Ergebnis der ursprüngliche Wert der Variablen ist."default"
bedeutet, dass das Ergebnis die bereitgestellte Ersatzzeichenfolge war.""
bedeutet, dass das Ergebnis null ist (eine leere Zeichenfolge).exit 127
bedeutet, dass das Skript mit dem Exit-Code 127 nicht mehr ausgeführt wird.$(VARIABLE="default")
bedeutet, dass das Ergebnis der ursprüngliche Wert der Variablen ist und die bereitgestellte Ersatzzeichenfolge der Variablen für die zukünftige Verwendung zugewiesen wird.quelle
VARIABLE=""
könnte geschrieben werden alsVARIABLE=
. Ersteres ist jedoch besser lesbar.Um zu sehen, ob eine Variable nicht leer ist, verwende ich
Das Gegenteil testet, ob eine Variable entweder nicht gesetzt oder leer ist:
Um zu sehen, ob eine Variable gesetzt ist (leer oder nicht leer), verwende ich
Das Gegenteil testet, ob eine Variable nicht gesetzt ist:
quelle
[ $isMac ] && param="--enable-shared"
${variable+x}
, umx
iff zu erhalten$variable
). Außerdem enthält es viel detailliertere Erklärungen, warum es richtig ist.${variable+x}
ist weniger lesbar (& offensichtlich)Bei einer modernen Version von Bash (4.2 oder höher, glaube ich; ich weiß es nicht genau) würde ich Folgendes versuchen:
quelle
[ -v "$VARNAME" ]
nicht falsch ist, sondern einfach einen anderen Test durchführt. Nehmen wir anVARNAME=foo
; Dann wird geprüft, ob eine Variable mit dem Namenfoo
gesetzt ist.-v
[: -v: unexpected operator
, muss man sicherstellen,bash
statt zu verwendensh
.Obwohl es für Argumente normalerweise am besten ist, $ # zu testen, was meiner Meinung nach die Anzahl der Argumente ist.
quelle
[ "$1" != "" ]
(oder[ -n "$1" ]
) ...$1
die leere Zeichenfolge festgelegt ist.$1
eine leere Zeichenfolge festgelegt ist.set -o nounset
es aktiviert ist.Hinweis
Ich gebe aufgrund des
bash
Tags eine stark auf Bash ausgerichtete Antwort .Kurze Antwort
Solange Sie nur mit benannten Variablen in Bash arbeiten, sollte diese Funktion Ihnen immer mitteilen, ob die Variable festgelegt wurde, auch wenn es sich um ein leeres Array handelt.
Warum das so ist
Wenn
var
es sich bei Bash (mindestens bis 3.0) um eine deklarierte / gesetzte Variable handelt, wirddeclare -p var
eindeclare
Befehl ausgegeben , der die Variablevar
auf den aktuellen Typ und Wert setzt und den Statuscode0
(Erfolg) zurückgibt . Wennvar
nicht deklariert ist, wirddeclare -p var
eine Fehlermeldung an denstderr
Statuscode ausgegeben und dieser zurückgegeben1
. Leitet mit&>/dev/null
und leitet sowohl regulärstdout
als auchstderr
Ausgabe an um/dev/null
, wird nie gesehen und ohne den Statuscode zu ändern. Somit gibt die Funktion nur den Statuscode zurück.Warum andere Methoden (manchmal) in Bash fehlschlagen
Wenn diese Methode in Bash fehlschlägt
Dies funktioniert nur bei benannten Variablen (einschließlich
$_
), nicht bestimmten Sondergrößen ($!
,$@
,$#
,$$
,$*
,$?
,$-
,$0
,$1
,$2
, ... und alle , die ich vergessen habe). Da es sich bei keinem dieser Arrays um Arrays handelt,[ -n "${var+x}" ]
funktioniert der POSIX-Stil für alle diese speziellen Variablen. Achten Sie jedoch darauf, dass Sie es nicht in eine Funktion einschließen, da viele spezielle Variablen beim Aufrufen von Funktionen Werte / Existenz ändern.Hinweis zur Shell-Kompatibilität
Wenn Ihr Skript Arrays enthält und Sie versuchen, es mit so vielen Shells wie möglich kompatibel zu machen, sollten Sie die Verwendung von
typeset -p
anstelle von in Betracht ziehendeclare -p
. Ich habe gelesen, dass ksh nur das erstere unterstützt, konnte dies aber nicht testen. Ich weiß, dass Bash 3.0+ und Zsh 5.5.1 beide unterstützentypeset -p
unddeclare -p
sich nur dadurch unterscheiden, dass eines eine Alternative für das andere ist. Aber ich habe keine Unterschiede über diese beiden Schlüsselwörter hinaus getestet, und ich habe keine anderen Shells getestet.Wenn Ihr Skript POSIX sh-kompatibel sein soll, können Sie keine Arrays verwenden. Ohne Arrays
[ -n "{$var+x}" ]
funktioniert.Vergleichscode für verschiedene Methoden in Bash
Diese Funktion deaktiviert die Variable
var
,eval
s den übergebenen Code, führt Tests aus, um festzustellen, obvar
dereval
d-Code festgelegt ist, und zeigt schließlich die resultierenden Statuscodes für die verschiedenen Tests an.Ich Skipping
test -v var
,[ -v var ]
und[[ -v var ]]
weil sie identische Ergebnisse an den POSIX - Standard ergeben[ -n "${var+x}" ]
, während erfordern Bash 4.2+. Ich überspringe auch,typeset -p
weil es das gleiche ist wiedeclare -p
in den Shells, die ich getestet habe (Bash 3.0 bis 5.0 und Zsh 5.5.1).Testfallcode
Beachten Sie, dass Testergebnisse unerwartet sein können, da Bash nicht numerische Array-Indizes als "0" behandelt, wenn die Variable nicht als assoziatives Array deklariert wurde. Außerdem sind assoziative Arrays nur in Bash 4.0+ gültig.
Testausgabe
Die Test Mnemonik in der Kopfzeile entsprechen
[ -n "$var" ]
,[ -n "${var+x}" ]
,[ "${#var[@]}" != 0 ]
, unddeclare -p var
ist.Zusammenfassung
quelle
declare -p var &>/dev/null
) die EINZIGE, die funktioniert. VIELEN DANK!... &> /dev/null
aber SO würde mich nicht ein einzelnes Zeichen bearbeiten lassen 🙄 (muss> 6 Zeichen sein - habe sogar versucht, Leerzeichen hinzuzufügen aber es hat nicht funktioniert). Es könnte sich auch lohnen, die Funktion zu ändern, um$1
für ein Beispiel mit dem Namen Variable (z. B.OUTPUT_DIR
) auszuschalten, da, wie Sie bereits betont haben, spezielle Variablen wie$1
hier nicht funktionieren. Auf jeden Fall ist es eine kritische Änderung, andernfalls versucht der Code, eine Datei zu erstellen, dienull
in einem relativen Verzeichnis namens aufgerufen wirddev
. Übrigens - tolle Antwort!declare -p PATH &> /dev/null
0declare -p ASDFASDGFASKDF &> /dev/null
zurück, wobei 1 zurückgegeben wird (bei Bash 5.0.11 (1) -Veröffentlichung)declare var
deklariert var als Variable, setzt es aber nicht in Bezug aufset -o nounset
: Test mitdeclare foo bar=; set -o nounset; echo $bar; echo $foo
/
! Ich habe das behoben, aber ich denke, die Logik ist verwirrend genug, um eine Funktion zu rechtfertigen, insbesondere angesichts des Kommentars von @ xebeche. @xebeche Das ist unpraktisch für meine Antwort.… Es sieht so aus, als müsste ich etwas wiedeclare -p "$1" | grep =
oder ausprobierentest -v "$1"
.Für diejenigen , die für ungesetzt zu überprüfen suchen oder leeren , wenn sie in einem Skript mit
set -u
:Die reguläre
[ -z "$var" ]
Prüfung schlägt mitvar; unbound variable
if fehl, wirdset -u
jedoch zu einer leeren Zeichenfolge[ -z "${var-}" ]
erweitert , wenn sievar
nicht fehlgeschlagen ist.quelle
${var:-}
nicht sein${var-}
. Aber in Bash kann ich bestätigen, dass es auch ohne Doppelpunkt funktioniert.${var:-}
und${var-}
verschiedene Dinge bedeuten.${var:-}
wird auf leere Zeichenfolge erweitert, wennvar
nicht gesetzt oder null, und${var-}
wird nur dann auf leere Zeichenfolge erweitert, wenn nicht gesetzt.Sie möchten beenden, wenn es nicht gesetzt ist
Das hat bei mir funktioniert. Ich wollte, dass mein Skript mit einer Fehlermeldung beendet wird, wenn kein Parameter festgelegt wurde.
Dies wird mit einem Fehler zurückgegeben, wenn es ausgeführt wird
Nur prüfen, kein Beenden - Leer und Nicht gesetzt sind UNGÜLTIG
Versuchen Sie diese Option, wenn Sie nur überprüfen möchten, ob der Wert set = VALID oder unset / empty = INVALID ist.
Oder auch kurze Tests ;-)
Nur prüfen, kein Ausgang - Nur leer ist UNGÜLTIG
Und das ist die Antwort auf die Frage. Verwenden Sie diese Option, wenn Sie nur überprüfen möchten, ob der Wert set / empty = VALID oder unset = INVALID ist.
HINWEIS, die "1" in "..- 1}" ist unbedeutend, es kann alles sein (wie x)
Kurze Tests
Ich widme diese Antwort @ mklement0 (Kommentare), der mich herausforderte, die Frage genau zu beantworten.
Referenz http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02
quelle
Verwenden Sie
[ -n "$x" ]
, wie andere bereits angegeben haben , um zu überprüfen, ob eine Variable mit einem nicht leeren Wert festgelegt ist .In den meisten Fällen empfiehlt es sich, eine Variable mit einem leeren Wert genauso zu behandeln wie eine nicht gesetzte Variable. Sie können die beiden jedoch unterscheiden, wenn Sie Folgendes benötigen:
[ -n "${x+set}" ]
("${x+set}"
Erweitert aufset
ifx
ist gesetzt und auf die leere Zeichenfolge, wenn nicht gesetztx
ist).Um zu überprüfen, ob ein Parameter übergeben wurde, testen Sie
$#
die Anzahl der Parameter, die an die Funktion (oder an das Skript, wenn sie nicht in einer Funktion enthalten sind) übergeben wurden (siehe Pauls Antwort ).quelle
Lesen Sie den Abschnitt "Parametererweiterung" auf der
bash
Manpage. Die Parametererweiterung bietet keinen allgemeinen Test für eine zu setzende Variable, aber es gibt verschiedene Möglichkeiten, einen Parameter zu bearbeiten, wenn er nicht gesetzt ist.Zum Beispiel:
wird
first_arg
gleich gesetzt,$1
wenn es zugewiesen ist, andernfalls wird der Wert "foo" verwendet. Wenna
unbedingt ein einzelner Parameter verwendet werden muss und kein guter Standardwert vorhanden ist, können Sie mit einer Fehlermeldung beenden, wenn kein Parameter angegeben wird:(Beachten Sie die Verwendung von
:
als Null-Befehl, der nur die Werte seiner Argumente erweitert.$1
In diesem Beispiel möchten wir nichts damit anfangen. Beenden Sie einfach, wenn er nicht festgelegt ist.)quelle
: ${var?message}
.In Bash können Sie
-v
innerhalb des[[ ]]
eingebauten verwenden:quelle
Die Verwendung
[[ -z "$var" ]]
ist der einfachste Weg, um festzustellen, ob eine Variable festgelegt wurde oder nicht.-z
Diese Option unterscheidet jedoch nicht zwischen einer nicht gesetzten Variablen und einer Variablen, die auf eine leere Zeichenfolge festgelegt ist:Am besten überprüfen Sie es nach dem Variablentyp: env-Variable, Parameter oder reguläre Variable.
Für eine env-Variable:
Für einen Parameter (zum Beispiel um die Existenz eines Parameters zu überprüfen
$5
):Für eine reguläre Variable (mit einer Hilfsfunktion, um dies auf elegante Weise zu tun):
Anmerkungen:
quelle
Die obigen Antworten funktionieren nicht, wenn die Bash-Option
set -u
aktiviert ist. Sie sind auch nicht dynamisch, z. B. wie wird getestet, ob eine Variable mit dem Namen "Dummy" definiert ist? Versuche dies:Verwandte Themen: Wie teste ich in Bash, ob eine Variable im Modus "-u" definiert ist?
quelle
eval "[ ! -z \${$1:-} ]"
Auswertung tun: Wechsel zur indirekten Bewertung :[ ! -z ${!1:-} ];
.Du kannst tun:
quelle
-n
und nicht negieren-z
.$1
, dh ,[ ! -z "$1" ]
. Oder Sie können[[ ! -z $1 ]]
in bash / ksh / zsh schreiben .$1
die leere Zeichenfolge festgelegt ist.Mein bevorzugter Weg ist folgender:
Wenn also eine Variable gesetzt ist, wird sie im Grunde genommen "eine Negation des Ergebnisses
false
" (was sein wirdtrue
= "wird gesetzt").Und wenn es nicht gesetzt ist, wird es "eine Negation des Ergebnisses
true
" (wie das leere Ergebnis ergibttrue
) (endet also alsfalse
= "NICHT gesetzt").quelle
Oder
Oder
Oder
quelle
In einer Shell können Sie den
-z
Operator True verwenden, wenn die Länge der Zeichenfolge Null ist.Ein einfacher Einzeiler zum Festlegen der Standardeinstellung,
MY_VAR
wenn diese nicht festgelegt ist. Andernfalls können Sie optional die folgende Meldung anzeigen:quelle
quelle
$1
,$2
Und bis zu$N
ist immer gesetzt. Entschuldigung, das ist fehlgeschlagen.Ich habe einen (viel) besseren Code gefunden, um dies zu tun, wenn Sie nach etwas suchen möchten
$@
.Warum das alles? Alles in
$@
ist in Bash vorhanden, aber standardmäßig ist es leertest -z
undtest -n
kann Ihnen nicht helfen.Update: Sie können auch die Anzahl der Zeichen in einem Parameter zählen.
quelle
quelle
Das benutze ich jeden Tag:
Dies funktioniert gut unter Linux und Solaris bis Bash 3.0.
quelle
test -n "$(eval "echo "\${${1}+x}"")"
[[ ${!1+x} ]]
Ich mag Hilfsfunktionen, um die groben Details von Bash zu verbergen. In diesem Fall wird dadurch noch mehr (versteckte) Grobheit hinzugefügt:
Da ich zum ersten Mal Fehler in dieser Implementierung hatte (inspiriert von den Antworten von Jens und Lionel), habe ich eine andere Lösung gefunden:
Ich finde es direkter, schüchterner und leichter zu verstehen / zu merken. Testfall zeigt, dass es äquivalent ist:
Der Testfall auch zeigt , dass
local var
sich NICHT var erklären (es sei denn , durch ‚=‘ folgt). Seit einiger Zeit dachte ich, ich hätte Variablen auf diese Weise deklariert, nur um jetzt herauszufinden, dass ich nur meine Absicht ausgedrückt habe ... Es ist ein No-Op, denke ich.BONUS: Anwendungsfall
Ich benutze diesen Test meistens, um Funktionen auf eine etwas "elegante" und sichere Weise (fast wie eine Schnittstelle ...) mit Parametern zu versehen (und zurückzugeben ):
Wenn mit all aufgerufen, müssen Variablen deklariert werden:
sonst:
quelle
Nachdem Sie alle Antworten überflogen haben, funktioniert dies auch:
Wenn Sie nicht
SOME_VAR
anstelle von dem setzen, was ich habe$SOME_VAR
, wird es auf einen leeren Wert gesetzt.$
ist notwendig, damit dies funktioniert.quelle
set -u
in der Tat haben, die denunboud variable
Fehler drucken wirdZusammenfassung
test -n "${var-}"
diese Option , um zu überprüfen, ob die Variable nicht leer ist (und daher auch definiert / gesetzt werden muss).test ! -z "${var+}"
diese Option , um zu überprüfen, ob die Variable definiert / festgelegt ist (auch wenn sie leer ist).Beachten Sie, dass der erste Anwendungsfall in Shell-Skripten viel häufiger vorkommt und dass Sie diesen normalerweise verwenden möchten.
Anmerkungen
Erläuterung
Um zu verstehen, wie diese Lösung funktioniert, müssen Sie den POSIX-
test
Befehl und die Erweiterung der POSIX-Shell-Parameter ( Spezifikation ) verstehen. Lassen Sie uns also die absoluten Grundlagen behandeln, die zum Verständnis der Antwort erforderlich sind.Der Testbefehl wertet einen Ausdruck aus und gibt true oder false zurück (über seinen Exit-Status). Der Operator
-n
gibt true zurück, wenn der Operand eine nicht leere Zeichenfolge ist. Gibt beispielsweisetest -n "a"
true zurück, währendtest -n ""
false zurückgegeben wird. Um zu überprüfen, ob eine Variable nicht leer ist (was bedeutet, dass sie definiert werden muss), können Sie sie verwendentest -n "$var"
. Einige Shell-Skripte verfügen jedoch über eine Option set (set -u
), die bewirkt, dass Verweise auf undefinierte Variablen einen Fehler ausgeben. Wenn die Variablevar
nicht definiert ist, verursacht der Ausdruck$a
einen Fehler. Um diesen Fall korrekt zu behandeln, müssen Sie die Variablenerweiterung verwenden, die die Shell anweist, die Variable durch eine alternative Zeichenfolge zu ersetzen, wenn sie nicht definiert ist, um den oben genannten Fehler zu vermeiden.Die Variablenerweiterung
${var-}
bedeutet: Wenn die Variablevar
undefiniert ist (auch als "nicht gesetzt" bezeichnet), ersetzen Sie sie durch eine leere Zeichenfolge. Gibt alsotest -n "${var-}"
true zurück, wenn$var
es nicht leer ist. Dies ist fast immer das, was Sie in Shell-Skripten einchecken möchten. Die umgekehrte Prüfung, ob$var
undefiniert oder nicht leer, wäretest -z "${var-}"
.Nun zum zweiten Anwendungsfall: Überprüfen, ob die Variable
var
definiert ist, ob leer oder nicht. Dies ist ein weniger verbreiteter und etwas komplexer Anwendungsfall, und ich würde Ihnen raten, die großartige Antwort von Lionels zu lesen , um sie besser zu verstehen.quelle
Um zu überprüfen, ob eine Variable gesetzt ist oder nicht
quelle
$var
die leere Zeichenfolge festgelegt ist.Wenn Sie testen möchten, ob eine Variable gebunden oder ungebunden ist, funktioniert dies auch dann, wenn Sie die Nomen-Set-Option aktiviert haben:
quelle
set -o nounset
nichtset -o noun set
. Dies funktioniert nur für Variablen, dieexport
bearbeitet wurden. Außerdem werden Ihre Einstellungen so geändert, dass das Rückgängigmachen umständlich ist.