15

Using bash, what's the best method to check if a variable is empty or not?

If I use:

if [ -z "$VAR" ]

as suggested in a forum this works for an unset variable but it is true when the variable is set but empty. Suggestions?

green69
  • 1,670
  • 3
  • 17
  • 21

6 Answers6

48

${var+set} substitutes nothing if the variable is unset and set if it is set to anything including the empty string. ${var:+set} substitutes set only if the variable is set to a non-empty string. You can use this to test for either case:

if [ "${foo+set}" = set ]; then
    # set, but may be empty
fi

if [ "${foo:+set}" = set ]; then
    # set and nonempty
fi

if [ "${foo-unset}" = unset ]; then
    # foo not set or foo contains the actual string 'unset'
    # to avoid a potential false condition in the latter case,
    # use [ "${foo+set}" != set ] instead
fi

if [ "${foo:-unset}" = unset ]; then
    # foo not set or foo empty or foo contains the actual string 'unset'
fi
dev
  • 1,648
  • 16
  • 25
geekosaur
  • 59,309
  • 11
  • 123
  • 114
  • 3
    just to round out this answer you might add that `-` works the opposite way, i.e., `${foo-unset}` yields 'unset' if foo is unset. this is useful for dry running scripts, e.g. `rsync -avuz ${DRYRUN---dry-run} $HOME/blog/ webserver:blog/` which must be run as `DRYRUN= upblog.sh` to actually perform the upload. – jcomeau_ictx Mar 19 '14 at 17:13
  • 1
    This should be the accepted answer. Edited answer to include @jcomeau_ictx's excellent comment. – dev Oct 15 '15 at 09:17
  • This is the best thing ever! You deserve 10000 upvotes @geekosaur – Mujtaba Mehdi Dec 04 '20 at 12:09
4

You can test with

[ -v name ]

name is without $ sign

mug896
  • 1,777
  • 1
  • 19
  • 17
  • I can't find this in either Bash v3.2.57(1) or v4.1.5(1). Which shell is this for? – tripleee Apr 06 '16 at 07:17
  • my bash shell version is 4.3 in ubuntu 15.10. check with "help test" command whether "-v" operator exist. actually there is two test commands one is shell builtin and the other is /usr/bin/test – mug896 Apr 10 '16 at 16:17
  • Since `-v` is not supported by POSIX, use `[[ ... ]]` rather than `[...]`. – chepner Sep 08 '20 at 17:47
3

Unset (non-existant) variables and empty variables behaves differently in parameter expansion:

In the following examples:
Without colon:

Checks only for variable existence.

With colon:

Checks for variable existence, if it exists, make sure that it's not empty.
In other words, checks both for variable existence and non-emptiness.


  • ${parameter:-word}
    If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

  • ${parameter-word}
    If parameter is unset...


  • ${parameter:=word}
    If parameter is unset or null, the expansion of word is assigned to parameter. The value of parameter is then substituted. Positional parameters and special parameters may not be assigned to in this way.

  • ${parameter=word}
    If parameter is unset...


  • ${parameter:?word}
    If parameter is unset or null, the expansion of word (or a message to that effect if word is not present) is written to the standard error and the shell, if it is not interactive, exits. Otherwise, the value of parameter is substituted.

  • ${parameter?word}
    If parameter is unset...


  • ${parameter:+word}
    If parameter is unset or null, nothing is substituted, otherwise the expansion of word is substituted.

  • ${parameter+word}
    If parameter is unset...


Source

Bohao LI
  • 2,123
  • 2
  • 18
  • 24
0

well, here's one way

$ s=""
$ declare -p s
declare -- s=""
$ unset s
$ declare -p s
bash: declare: s: not found

an error message will occur if the variable is unset.

kurumi
  • 25,121
  • 5
  • 44
  • 52
  • The original question was how to distinguish between variables that are set to the empty string versus variables that are not set at all. This returns blank for both cases. – Kevin Beck Mar 23 '11 at 15:22
  • @KevinBeck, eh? `declare -- s=""` is not an empty string, so it doesn't "return blank" in that case; and anyhow, you can just check exit status: `if declare -p s &>/dev/null; then echo "Variable s is set"; else echo "Variable s is unset"; fi`. I'm not upvoting this because there are better choices (more portable, easier-to-read); but it certainly does _work_. – Charles Duffy Sep 01 '20 at 14:51
-2
if [ `set | grep '^VAR=$'` ]

This searches for the string "VAR=" in the list of variables set.

Kevin Beck
  • 2,394
  • 2
  • 15
  • 27
  • I don't know who vote you down, but your solution works to me! – green69 Mar 23 '11 at 14:52
  • I answered the wrong question the first time. Here is a corrected answer. – Kevin Beck Mar 23 '11 at 14:56
  • 4
    My downvote is because this is unidiomatic, clumsy, and inefficient. The shell has built-in functionality for this; in addition, you have a [useless use of backticks](http://www.iki.fi/era/unix/award.html#backticks) and apparently [an incomplete understanding of what the `if` statement does.](http://stackoverflow.com/questions/36371221/bash-if-statement-too-many-arguments/36371520#36371520) – tripleee Apr 06 '16 at 07:14
  • 2
    If you're going to use this approach, it should at least be changed to `if set | grep -q '^VAR=$'; then ...` – Tom Fenech Apr 06 '16 at 08:19
-3

This would be true only for empty, not unset (or has value)

[ -z ${VAR-X}
  • 1
    Welcome to stackoverflow. Please elaborate a bit more on how this approach works than the accepted answer. – Nabil Farhan Sep 20 '19 at 02:22
  • This is simply buggy. It needs quotes around the expansion and a closing `]` (or a change from `[` to `test`) to function correctly. – Charles Duffy Sep 01 '20 at 14:53