Skip to content

Instantly share code, notes, and snippets.

@JoeyBurzynski
Created May 3, 2016 13:12
Show Gist options
  • Save JoeyBurzynski/f185285602b3c9f0fe708e32ad3ea06f to your computer and use it in GitHub Desktop.
Save JoeyBurzynski/f185285602b3c9f0fe708e32ad3ea06f to your computer and use it in GitHub Desktop.
Bash Scripting: Check if a Bash Variable Has Been Set (Or Is Empty String)
# How to determine if a bash variable is empty?
# A variable in bash (and any POSIX-compatible shell) can be in one of three states:
#
# unset
# set to the empty string
# set to a non-empty string
# Most of the time you only need to know if a variable is set to a non-empty string, but occasionally it's important to distinguish between unset and set # to the empty string.
#
# The following are examples of how you can test the various possibilities, and it works in bash or any POSIX-compatible shell:
if [ -z "${VAR}" ]; then
echo "VAR is unset or set to the empty string"
fi
if [ -z "${VAR+set}" ]; then
echo "VAR is unset"
fi
if [ -z "${VAR-unset}" ]; then
echo "VAR is set to the empty string"
fi
if [ -n "${VAR}" ]; then
echo "VAR is set to a non-empty string"
fi
if [ -n "${VAR+set}" ]; then
echo "VAR is set, possibly to the empty string"
fi
if [ -n "${VAR-unset}" ]; then
echo "VAR is either unset or set to a non-empty string"
fi
# Here is the same thing but in handy table form:
#
# +-------+-------+-----------+
# VAR is: | unset | empty | non-empty |
# +-----------------------+-------+-------+-----------+
# | [ -z "${VAR}" ] | true | true | false |
# | [ -z "${VAR+set}" ] | true | false | false |
# | [ -z "${VAR-unset}" ] | false | true | false |
# | [ -n "${VAR}" ] | false | false | true |
# | [ -n "${VAR+set}" ] | false | true | true |
# | [ -n "${VAR-unset}" ] | true | false | true |
# +-----------------------+-------+-------+-----------+
# The ${VAR+foo} construct expands to the empty string if VAR is unset or to foo if VAR is set to anything (including the empty string).
#
The ${VAR-foo} construct expands to the value of VAR if set (including set to the empty string) and foo if unset. This is useful for providing user-overridable defaults (e.g., ${COLOR-red} says to use red unless the variable COLOR has been set to something).
#
# The reason why [ x"${VAR}" = x ] is often recommended for testing whether a variable is either unset or set to the empty string is because some implementations of the [ command (also known as test) are buggy. If VAR is set to something like -n, then some implementations will do the wrong thing when given [ "${VAR}" = "" ] because the first argument to [ is erroneously interpreted as the -n operator, not a string.
# In Bash, when you're not concerned with portability to shells that don't support it, you should always use the double-bracket syntax:
# Any of the following:
if [[ -z $variable ]]
if [[ -z "$variable" ]]
if [[ ! $variable ]]
if [[ ! "$variable" ]]
# In Bash, using double square brackets, the quotes aren't necessary. You can simplify the test for a variable that does contain a value to:
if [[ $variable ]]
# This syntax is compatible with ksh (at least ksh93, anyway). It does not work in pure POSIX or older Bourne shells such as sh or dash.
# You can test to see if a variable is specifically unset (as distinct from an empty string):
if [[ -z ${variable+x} ]] # where the "x" is arbitrary.
# If you want to know whether a variable is null but not unset:
if [[ -z $variable && ${variable+x} ]]
# This will return true if a variable is unset or set to the empty string ("").
if [ -z "$VAR" ];
# the inverse of -z is -n if [ -n "$VAR" ];
# How can I test if a variable is empty or contains only spaces?
# First, note that the -z test is explicitly for:
#
# the length of string is zero
# That is, a string containing only spaces should not be true under -z, because it has a non-zero length.
#
# What you want is to remove the spaces from the variable using the pattern replacement parameter expansion:
[[ -z "${param// }" ]]
# This expands the param variable and replaces all matches of the pattern (a single space) are deleted, so a string that has only spaces in it will be expanded to an empty string.
#
# The nitty-gritty of how that works is that ${var/pattern/string} replaces the first longest match of pattern with string. When pattern starts with / (as above) then it replaces all the matches. Because the replacement is empty, we can omit the final / and the string value:
${parameter/pattern/string}
# The pattern is expanded to produce a pattern just as in filename expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with ‘/’, all matches # of pattern are replaced with string. Normally only the first match is replaced. ... If string is null, matches of pattern are deleted and the / following pattern may be omitted.
# After all that, we end up with ${param// } to delete all spaces.
# Note that though present in ksh (where it originated), zsh and bash, that syntax is not POSIX and should not be used in sh scripts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment