4341
Comment: Add a few
|
2487
test -v (bash 4.2-4.3)
|
Deletions are marked like this. | Additions are marked like this. |
Line 3: | Line 3: |
There are several ways to test for a defined or non-empty variable or function depending upon the requirements. <<TableOfContents>> === "Declared", "Defined", and "Undefined" === Like in many languages, ''declaration'' and ''definition'' can be independent steps. To declare an object is to give it a name and datatype, whereas a definition associates it with a value, which may be empty. In Unix shell terminology, "unset", "set", and "null" are often used to mean "undefined", "defined", and "empty" respectively. Since "string" is very nearly the only common datatype, "null" usually means the empty string. With arrays, things become less consistent between shells. === Testing for a defined, non-empty variable / parameter. === Since the most common goal is to distinguish between an empty and non-empty variable or parameter, we'll discuss it first. These are the most common solutions arranged from most to least portable. || `test x"$var" != x` || Only needed for ancient Bourne shells. Don't use this in modern scripts. || || `test -n "$var"` || POSIX sh plus some older Bourne shells which lacked `[`. || || `[ -n "$var" ]` || POSIX sh and most Bourne shells including Heirloom. Best overall choice for new scripts requiring POSIX compatibility. || || `test "$var"` || POSIX sh. POSIX specifies that for one argument, non-null is always true while null is always false. || || `[ "$var" ]` || POSIX sh. As above. Still very portable. || || `[[ -n $var ]]` || Here and below is Bash/Ksh/Zsh only. This is compatible with some buggy shell versions which didn't process the implicit -n correctly. || || `[[ $var ]]` || Best overall choice for Bash/Ksh where POSIX isn't a requirement. Usually best performance. This won't work in Zsh. || || `(( ${#var} ))` || About as portable as the above. Almost always slower. Don't use this to test for empty strings. || To check the converse, whether a variable is empty (unset or zero-length), invert the above logic. |
There are several ways to test these things, depending on the exact requirements. Most of the time, the desired test is ''whether a variable has a non-empty value''. In this case, we may simply use: |
Line 27: | Line 6: |
test x"$var" = x test -z "$var" [ -z "$var" ] test ! "$var" [ ! "$var" ] [[ -z $var ]] [[ ! $var ]] # Also won't work in Zsh in any emulate mode. If such portability is needed, adjust solutions on this page to use -z or -n explicitly. |
# POSIX if test "$var"; then echo "The variable has a non-empty value." fi |
Line 36: | Line 12: |
=== Testing that a variable has been declared === | If this fails for you because you use `set -u`, please see [[BashFAQ/112|FAQ 112]]. |
Line 38: | Line 14: |
Distinguishing between a variable that is ''undefined'' and one that is ''defined but empty'' is somewhat trickier, but possible. | If we wish to distinguish between an ''empty'' variable and an ''unset'' variable, then we may use the `+` [[BashFAQ/073|parameter expansion]]: |
Line 41: | Line 17: |
# POSIX. Not Bourne-compatible. ! ${var+false} # Usually fastest and cleanest. [ "$((${var+1}))" -ne 0 ] # Bourne / POSIX ${var+:} false [ -n "${var+_}" ] [ "${var+_}" ] |
# POSIX if test "${var+defined}"; then echo "The variable is defined." fi |
Line 51: | Line 23: |
Which of the above performs best varies from shell to shell. If POSIX isn't a requirement, the following `[[` solution usually performs best. | The magic here is the `+`, ''not'' the word `defined`. We can use any non-empty word after the `+` sign. I prefer `defined` because it indicates what kind of test is being performed. Some people prefer the `-v` option that was added in bash 4.2: |
Line 54: | Line 28: |
# Bash/ksh [[ ${var+_} ]] (( ${var+1} )) |
# Bash 4.2 and up # Bash 4.3 if you want to test an array element if test -v var; then echo "The variable is defined." fi |
Line 59: | Line 35: |
Another method that's occasionally seen is to check the status of `typeset -p`. The above method should be preferred over this. | There's really no benefit to this over the portable test, though. === Setting a default value === If what we really want is to set a variable to a default value ''unless it already has a value'', then we may skip the test, and use the `=` parameter expansion: |
Line 62: | Line 42: |
# Bash/ksh/zsh typeset -p var >/dev/null 2>&1 # returns 0 if var exists, error otherwise |
# POSIX : "${var=default}" |
Line 67: | Line 46: |
Bash 4.2 adds a `-v` test: | See [[BashFAQ/073|FAQ 73]] for details. |
Line 69: | Line 48: |
{{{ # Bash 4.2 / ksh93 if [[ -v var ]]; then echo "var is defined"; fi }}} |
=== Testing whether a function has been defined === |
Line 74: | Line 50: |
ksh93 additionally supports array indices with the `-v` test, while Bash so far does not. This should be the preferred method when targeting ksh93 specifically. === Testing that a function has been defined === For determining whether a function with a given name is already defined, there are several answers, all of which require Bash (or at least, non-Bourne) commands. Testing that a function is defined should rarely be necessary. |
For determining whether a function with a given name is already defined, there are several answers, all of which require Bash (or at least, non-Bourne) commands. Testing that a function is defined should rarely be necessary. Just define the function as you want it to be defined instead of worrying about what might or might not have been inherited from who-knows-where. |
How do I determine whether a variable is already defined? Or a function?
There are several ways to test these things, depending on the exact requirements. Most of the time, the desired test is whether a variable has a non-empty value. In this case, we may simply use:
# POSIX if test "$var"; then echo "The variable has a non-empty value." fi
If this fails for you because you use set -u, please see FAQ 112.
If we wish to distinguish between an empty variable and an unset variable, then we may use the + parameter expansion:
# POSIX if test "${var+defined}"; then echo "The variable is defined." fi
The magic here is the +, not the word defined. We can use any non-empty word after the + sign. I prefer defined because it indicates what kind of test is being performed.
Some people prefer the -v option that was added in bash 4.2:
# Bash 4.2 and up # Bash 4.3 if you want to test an array element if test -v var; then echo "The variable is defined." fi
There's really no benefit to this over the portable test, though.
Setting a default value
If what we really want is to set a variable to a default value unless it already has a value, then we may skip the test, and use the = parameter expansion:
# POSIX : "${var=default}"
See FAQ 73 for details.
Testing whether a function has been defined
For determining whether a function with a given name is already defined, there are several answers, all of which require Bash (or at least, non-Bourne) commands. Testing that a function is defined should rarely be necessary. Just define the function as you want it to be defined instead of worrying about what might or might not have been inherited from who-knows-where.
declare -F f >/dev/null # Bash only - declare outputs "f" and returns 0 if defined, returns non-zero otherwise. typeset -f f >/dev/null # Bash/Ksh - typeset outputs the entire function and returns 0 if defined, returns non-zero otherwise. [[ $(type -t f) = function ]] # Bash-only - "type" outputs "function" if defined. In ksh (and mksh), the "type" alias for "whence -v" differs. # Bash/Ksh. Workaround for the above, but the first two are preferable. isFunction() [[ $(type ${BASH_VERSION:+-t} "$1") == ${KSH_VERSION:+"$1 is a "}function ]]; isFunction f