Differences between revisions 25 and 26
Revision 25 as of 2016-07-24 18:05:27
Size: 4541
Editor: atlantic850
Comment:
Revision 26 as of 2016-11-23 18:40:14
Size: 2211
Editor: GreyCat
Comment: Reset button. Start over. My god, what was all that noise? Now wait and see how long until the page is re-vandalized by the well-meaning.
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 and not so ancient pdksh or ash versions. 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 ]]` || Also works in Bash, Ksh and Zsh since version 5.0.6. Same as above, only more ambiguous. ||
|| `(( ${#var} ))` || About as portable as the above though hits some bugs in some versions of Ksh when the variable contains invalid characters. Almost always slower. Don't use this to test for empty strings. ||
|| `case "$var" in "")` || Extremely portable. You'll probably want to use that if you want to check for different values including the empty string. ||

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 28: Line 6:
test x"$var" = x
test -z "$var"
[ -z "$var" ]
test ! "$var"
[ ! "$var" ]
[[ -z $var ]]
[[ ! $var ]] # Also won't work in Zsh prior to 5.0.6. If such portability is needed, adjust solutions on this page to use -z or -n explicitly.
case "$var" in "") ;; *)...
# POSIX
if test "$var"; then
  echo "The variable has a non-empty value."
fi
Line 38: 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 40: 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 43: Line 17:
# Bourne / POSIX:
${var+':'} false
case ${var+y} in y)...
[ -n "${var+_}" ]
# POSIX
if test "${var+defined}"; then
  echo "The variable is defined."
fi
Line 49: 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.

=== 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 52: Line 30:
# Bash/ksh
[[ ${var+_} ]]
(( ${var+1} ))
# POSIX
: "${var=default}"
Line 57: Line 34:
Another method that's occasionally seen is to check the status of `typeset -p`. The above method should be preferred over this. See [[BashFAQ/073|FAQ 73]] for details.
Line 59: Line 36:
{{{
# Bash/ksh/zsh
typeset -p var >/dev/null 2>&1
# returns 0 if var exists, error otherwise
}}}
=== Testing whether a function has been defined ===
Line 65: Line 38:
Bash 4.2 adds a `-v` test:

{{{
# Bash 4.2 / ksh93
if [[ -v var ]]; then echo "var is defined"; fi
}}}

ksh93 and bash (since 4.3) support array indices with the `-v` test. Bash 4.2 did not. This is the "best" but also least portable method to test for an unset variable.

=== 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.

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

BashFAQ/083 (last edited 2022-11-26 06:06:57 by emanuele6)