2

I am using the code below to determine if a variable in bash exists, if it is empty, or if it has length>0. The code works, but I can't find a good explanation for how if [ -n "${emptyvar+1}" ] can detect if emptyvar is not set. If I remove the +1 then the test fails for "". What is the purpose of the +1 in the test?

#!/bin/bash

emptyvar="a"

if [ -n "${emptyvar+1}" ]
  then
    echo "emptyvar is defined"
    if [[ -z $emptyvar ]]
      then
         echo "emptyvar is empty"; 
      else
         echo "emptyvar is NOT empty"; 
        if [[ -n $emptyvar ]]
          then
             echo "emptyvar has length > 0"; 
          else
             echo "emptyvar has length 0"; 
        fi
    fi
  else
    echo "emptyvar is not defined"
fi

4 Answers 4

4

From the bash documentation of Shell Parameter Expansion:

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

Omitting the colon (:) makes it test only if the variable is unset, rather than null or unset.

So ${emptyvar+1} tests if $emptyvar is unset. If it is, it expands to the empty string; if not, it expands to 1.

Sign up to request clarification or add additional context in comments.

3 Comments

But why this +1 is needed in OP's case since checking [[ -n "$emptyvar" ]] should also do the job.
That will not distinguish between a variable that's unset and a variable that's set to the empty string.
@anubhava See the third if, which uses that test.
1

You can also create sets of functions to test a variable passed by its name:

function is_var_set {
    [[ -n ${!1+.} ]]
}

function is_var_empty {
    [[ -z ${!1} ]]
}

Test:

> A=''
> is_var_set A && echo "A is set." || echo "A is unset."
A is set.
> is_var_empty A && echo "A is empty." || echo "A is not empty."
A is empty.

Comments

1

bash 4.2 added a new test operator, -v, that tests if a variable has been set.

# -v takes the name of the variable, not its values (since you are
# testing if it has a value or not).
if [[ -v emptyvar ]]; then
    echo "emptyvar is defined"
    if [[ -z $emptyvar ]]
      then
         echo "emptyvar is empty"; 
      else
         echo "emptyvar is NOT empty"; 
    fi
  else
    echo "emptyvar is not defined"
fi

Note that an empty variable is one whose string has length 0, so your -n test is redundant.

3 Comments

I tested it on my mac and on Ubuntu 10.04 and got an error. Maybe they are not 4.2? Error: ./a.sh: line 5: conditional binary operator expected ./a.sh: line 5: syntax error near emptyvar' ./a.sh: line 5: if [[ -v emptyvar ]]; then' Line 5 is if [[ -v emptyvar ]]; then
Check the value of $BASH_VERSION. Mac OS X ships with 3.2, and I suspect Ubuntu 10.04 ships with 4.1.
That's it. Thanks. Mac is 3.2.51(1)-release and Ubuntu is 4.1.5(1)-release
0

Another way to express it:

$ unset var
$ if [[ -z ${var+x} ]]; then echo unset; elif [[ -z $var ]]; then echo empty; else echo not empty; fi
unset
$ var=
$ if [[ -z ${var+x} ]]; then echo unset; elif [[ -z $var ]]; then echo empty; else echo not empty; fi
empty
$ var=foo
$ if [[ -z ${var+x} ]]; then echo unset; elif [[ -z $var ]]; then echo empty; else echo not empty; fi
not empty

You'll never get "emptyvar has length 0" -- that's what "empty" is

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.