How can I test if a variable is empty or contains only spaces?

The following bash syntax verifies if param isn’t empty:

 [[ !  -z  $param  ]]

For example:

param=""
[[ !  -z  $param  ]] && echo "I am not zero"

No output and its fine.

But when param is empty except for one (or more) space characters, then the case is different:

param=" " # one space
[[ !  -z  $param  ]] && echo "I am not zero"

“I am not zero” is output.

How can I change the test to consider variables that contain only space characters as empty?

Asked By: maihabunash

||

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) with nothing, 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.

Answered By: Michael Homer

The only remaining reason to write a shell script, instead of a script in a good scripting language, is if extreme portability is an overriding concern. The legacy /bin/sh is the only thing you can be certain you have, but Perl for instance is more likely to be available cross-platform than Bash. Therefore, never write shell scripts that use features that aren’t truly universal — and keep in mind that several proprietary Unix vendors froze their shell environment prior to POSIX.1-2001.

There is a portable way to make this test, but you have to use tr:

[ "x`printf '%s' "$var" | tr -d "$IFS"`" = x ]

(The default value of $IFS, conveniently, is a space, a tab, and a newline.)

(The printf builtin is itself spottily portable, but relying on it is much less hassle than figuring out which variant of echo you have.)

Answered By: zwol

The easy way to check that a string only contains characters in an authorized set is to test for the presence of unauthorized characters. Thus, instead of testing whether the string only contains spaces, test whether the string contains some character other than space. In bash, ksh or zsh:

if [[ $param = *[! ]* ]]; then
  echo "$param contains characters other than space"
else
  echo "$param consists of spaces only"
fi

“Consists of spaces only” includes the case of an empty (or unset) variable.

You may want to test for any whitespace character. Use [[ $param = *[^[:space:]]* ]] to use locale settings, or whatever explicit list of whitespace characters you want to test for, e.g. [[ $param = *[$' tn']* ]] to test for space, tab or newline.

Matching a string against a pattern with = inside [[ … ]] is a ksh extension (also present in bash and zsh). In any Bourne/POSIX-style, you can use the case construct to match a string against a pattern. Note that standard shell patterns use ! to negate a character set, rather than ^ like in most regular expression syntaxes.

case "$param" in
  *[! ]*) echo "$param contains characters other than space";;
  *) echo "$param consists of spaces only";;
esac

To test for whitespace characters, the $'…' syntax is specific to ksh/bash/zsh; you can insert these characters in your script literally (note that a newline will have to be within quotes, as backslash+newline expands to nothing), or generate them, e.g.

whitespace=$(printf 'nt ')
case "$param" in
  *[!$whitespace]*) echo "$param contains non-whitespace characters";;
  *) echo "$param consists of whitespace only";;
esac

For testing if variable is empty or contain spaces, you can also use this code:

${name:?variable is empty}
Answered By: pratik

POSIXly:

case $var in
  (*[![:blank:]]*) echo '$var contains non blank';;
  (*) echo '$var contains only blanks or is empty or unset'
esac

To differentiate between blank, non-blank, empty, unset:

case ${var+x$var} in
  (x) echo empty;;
  ("") echo unset;;
  (x*[![:blank:]]*) echo non-blank;;
  (*) echo blank
esac

[:blank:] is for horizontal spacing characters (space and tab in ASCII, but there are probably a few more in your locale; some systems will include the non-breaking space (where available), some won’t). If you want vertical spacing characters as well (like newline or form-feed), replace [:blank:] with [:space:].

Answered By: Stéphane Chazelas
if [[ -n "${variable_name/[ ]*n/}" ]]
then
    #execute if the the variable is not empty and contains non space characters
else
    #execute if the variable is empty or contains only spaces
fi
Answered By: Guru

Try this:

$ [[ -z `echo $n` ]] && echo zero

zero
Answered By: Hugo

The code you posted [[ ! -z $param ]] && echo "I am not zero" will print I am not zero if param is either unset/undefined or empty (in bash, ksh and zsh).

To also print if param contains only spaces (remove spaces), POSIXly (for a wider range of shells):

 [   -z "${param#"${param%%[! ]*}"}"   ] && echo "empty"

Explanation:

  • A ${param# … } removes a leading text.
  • That leading text is given by: ${param%%[! ]*}
  • Which expands to all spaces before any non-space character, i.e. all the leading spaces.

The end result of the whole expansion is that all leading spaces get removed.

This expanded result is tested if of length 0.

  • If the result is empty, then either the variable was empty, or
  • removing the leading spaces made it empty.

Therefore, if the test is true, the variable was either empty already or only had spaces inside it.


The concept is easy to extend to more character types. To also include tabs, place an explicit tab inside the bracket expression:

 [ -z "${param#"${param%%[!     ]*}"}" ] && echo "empty"

or use a variable with the characters that you need removed:

 var=$' t'                                    # in ksh, bash, zsh
 [ -z "${param#"${param%%[!$var]*}"}" ] && echo "empty"

or you can use some POSIX “character class expression” (blank means space and tab):

 [ -z "${param#"${param%%[![:blank:]]*}"}" ] && echo "empty"
Answered By: user232326

To check if variable has only spaces, including in a multi-line variable, try this:

[[ $var = *[$" tn"]* ]]

Or with xargs:

[[ -z $(echo $var | xargs) ]]

Or with sed:

[[ -z $(sed "/^$/d" <<< $var) ]]
Answered By: Noam Manos

I prefer the solution without trimming

BLANK_STRING_REGEX='^ *$'
TEXT="  "
if [[ $TEXT =~ $BLANK_STRING_REGEX ]] ; then
    echo "Blank string"
fi

I’ve also noticed that it’s often useful to check whether a string contains spaces and new line chars only:

BLANK_STRING_REGEX='^s*$'
TEXT="  
    
"
if [[ $TEXT =~ $BLANK_STRING_REGEX ]] ; then
    echo "Blank string"
fi
Answered By: ka3ak
echo ${param//*[^[:space:]]*/I am not zero}
Answered By: nezabudka

I prefer this:

[[ $(echo "$param" | awk '{print NF}') -eq 0 ]]
Answered By: kkd
Categories: Answers Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.