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.
test: -n +x #@ -p
var=foo: 0 0 0 0
var=(foo): 0 0 0 0
var=([0]=foo): 0 0 0 0
var=([x]=foo): 0 0 0 0
var=([y]=bar [x]=foo): 0 0 0 0
var='': 1 0 0 0
var=([0]=''): 1 0 0 0
var=([1]=''): 1 1 0 0
var=([1]=foo): 1 1 0 0
declare -A var; var=([x]=foo): 1 1 0 0
var=(): 1 1 1 0
declare -a var: 1 1 1 0
declare -A var: 1 1 1 0
unset var: 1 1 1 1
Zusammenfassung
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.
if test $# -gt 0; then printf 'arg <%s>\n' "$@"; fi.