In modern bash (version 4.2 and above):

[[ -v name_of_var ]]

From help test:

-v VAR, True if the shell variable VAR is set

Answer from Chris Down on Stack Exchange
Top answer
1 of 12
156

In modern bash (version 4.2 and above):

[[ -v name_of_var ]]

From help test:

-v VAR, True if the shell variable VAR is set

2 of 12
49

Depends what you mean by exists.

Does a variable that has been declared but not assigned exist?

Does an array (or hash) variable that has been assigned an empty list exist?

Does a nameref variable pointing to a variable that currently isn't assigned exist?

Do you consider $-, $#, $1 variables? (POSIX doesn't).

In Bourne-like shells, the canonical way is:

if [ -n "${var+set}" ]; then
  echo '$var was set'
fi

That works for scalar variables and other parameters to tell if a variable has been assigned a value (empty or not, automatically, from the environment, assigments, read, for or other).

For shells that have a typeset or declare command, that would not report as set the variables that have been declared but not assigned (note that in zsh, declaring a variable assigns a value, a default one if not specified).

For shells that support arrays, except for yash and zsh that would not report as set array variables unless the element of indice 0 has been set.

For bash (but not ksh93 nor zsh), for variables of type associative array, that would not report them as set unless their element of key "0" has been set.

For ksh93 and bash, for variables of type nameref, that only returns true if the variable referenced by the nameref is itself considered set.

For ksh, zsh and bash, a potentially better approach could be:

if ((${#var[@]})); then
  echo '$var (or the variable it references for namerefs) or any of its elements for array/hashes has been set'
fi

For ksh93, zsh and bash 4.4 or above, there's also:

if typeset -p var 2> /dev/null | grep -q '^'; then
  echo '$var exists'
fi

Which will report variables that have been set or declared.

Top answer
1 of 16
3460

(Usually) The right way

if [ -z ${var+x} ]; then echo "var is unset"; else echo "var is set to '$var'"; fi

where ${var+x} is a parameter expansion which evaluates to nothing if var is unset, and substitutes the string x otherwise.

Quotes Digression

Quotes can be omitted (so we can say ${var+x} instead of "${var+x}") because this syntax & usage guarantees this will only expand to something that does not require quotes (since it either expands to x (which contains no word breaks so it needs no quotes), or to nothing (which results in [ -z ], which conveniently evaluates to the same value (true) that [ -z "" ] does as well)).

However, while quotes can be safely omitted, and it was not immediately obvious to all (it wasn't even apparent to the first author of this quotes explanation who is also a major Bash coder), it would sometimes be better to write the solution with quotes as [ -z "${var+x}" ], at the very small possible cost of an O(1) speed penalty. The first author also added this as a comment next to the code using this solution giving the URL to this answer, which now also includes the explanation for why the quotes can be safely omitted.

(Often) The wrong way

if [ -z "$var" ]; then echo "var is blank"; else echo "var is set to '$var'"; fi

This is often wrong because it doesn't distinguish between a variable that is unset and a variable that is set to the empty string. That is to say, if var='', then the above solution will output "var is blank".

The distinction between unset and "set to the empty string" is essential in situations where the user has to specify an extension, or additional list of properties, and that not specifying them defaults to a non-empty value, whereas specifying the empty string should make the script use an empty extension or list of additional properties.

The distinction may not be essential in every scenario though. In those cases [ -z "$var" ] will be just fine.

2 of 16
1399

To check for non-null/non-zero string variable, i.e. if set, use

if [ -n "$1" ]

It's the opposite of -z. I find myself using -n more than -z.

You would use it like:

if [ -n "$1" ]; then
  echo "You supplied the first parameter!"
else
  echo "First parameter not supplied."
fi
🌐
nixCraft
cyberciti.biz › nixcraft › howto › bash shell › how to check if a variable is set in bash
How to check if bash variable defined in script - nixCraft
March 14, 2024 - We can pass the -z option to the if command or conditional expression to check if a bash variable defined in script or not. Return true if a bash variable is unset or set to the empty string: if [ -z ${my_variable+x} ];
🌐
GeeksforGeeks
geeksforgeeks.org › linux-unix › bash-scripting-how-to-check-if-variable-is-set
Bash Scripting - How to check If variable is Set - GeeksforGeeks
December 12, 2023 - As we can see in the above output the condition returns true if the variable is defined. Even if the variable might be an empty string, it will return true. #!/usr/bin/env bash if [ -v k ];then echo "Variable is set" else echo "Variable is not set" fi
🌐
nixCraft
cyberciti.biz › nixcraft › howto › bash shell › bash shell: find out if a variable is set or not
Bash Shell: Find Out If a Variable Is Set or Not - nixCraft
December 14, 2021 - Explains how to find out if a bash variable is set (defined) or not under Unix / Linux like operating systems.
🌐
LinuxSimply
linuxsimply.com › home › bash scripting tutorial › bash conditional statements › if else in bash › check if a variable exists in bash using if statement
Check If a Variable Exists in Bash Using If Statement - LinuxSimply
January 23, 2024 - The -n operator in Bash is utilized to check if a variable exists by verifying whether its length is non-zero. When combined with an “if else” statement, it allows you to create conditional logic based on whether a variable has been defined ...
Top answer
1 of 3
3

Such a test does not exist as it might in a high-level language such as Java or C#, but it is relatively easy to construct.

Three comments on your question as asked:

1: You do not work with literal "true"/"false" values in bash; all commands and conditional constructs yield an exit status, or logical result, which is either 0 (true) or non-0 (false).
Work with this, don't try to re-invent the wheel.

2: Try not to use upper-case parameter names unless they are environment variables; this is a simple convention that helps keep your code clean.

3: What, exactly, do you mean by "NULL"? The literal string NULL, an empty value, or something else?
The latter two concepts don't exist in bash; a NULL variable would be unset, which you're already checking for.

The most effective solution would be a function that accepts a variable (or parameter, as bash calls them), and checks for those conditions, then sets the exit status based on that, effectively condensing multiple truth values to a literal 0 or 1.

For example:

is_true() { if [[ "$1" = 0 ]]; then false; elif [[ -z "$1" ]]; then false; elif [[ "$1" =~ [Ff][Aa][Ll][Ss][Ee] ]]; then false; fi; }

  • is_true "1" yields 0, which is true
  • is_true "false" yields 1, which is false
  • a=10; is_true "$a" yields 0
  • grep -q something somefile yields 0 if something appears at least once in somefile.

NOTE that the latter example clearly shows that you don't NEED such a construct; everything that happens in bash already works with these basic 0/1 truth values.

But I'll grant that you might have to convert input from some gnarly external program :)

2 of 3
3

I find these comparisons unuseful because they make appearance of code obscur and unobvious. I just use the nice feature of bash, that comes since v4.2, from the manpage:

   -v varname
          True if the shell variable varname is set (has been assigned a value).

Usage is very simple

OUTPUT_TO_LOG=1
if [ -v OUTPUT_TO_LOG ]; then
    exec > &>./logfile
    …
fi

In other words, to flag as enabled, just define. Try it!

$ :() { if [ -v VAR ]; then echo 'existed'; fi }
$ unset VAR && :          # no output
$ unset VAR && VAR= && :  # "existed"
$ unset VAR && VAR=1 && : # "existed"
Find elsewhere
Top answer
1 of 12
157

I think the answer you are after is implied (if not stated) by Vinko's answer, though it is not spelled out simply. To distinguish whether VAR is set but empty or not set, you can use:

if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi

You probably can combine the two tests on the second line into one with:

if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi

However, if you read the documentation for Autoconf, you'll find that they do not recommend combining terms with '-a' and do recommend using separate simple tests combined with &&. I've not encountered a system where there is a problem; that doesn't mean they didn't used to exist (but they are probably extremely rare these days, even if they weren't as rare in the distant past).

You can find the details of these, and other related shell parameter expansions, the test or [ command and conditional expressions in the Bash manual.


I was recently asked by email about this answer with the question:

You use two tests, and I understand the second one well, but not the first one. More precisely I don't understand the need for variable expansion

if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fi

Wouldn't this accomplish the same?

if [ -z "${VAR}" ]; then echo "VAR is not set at all"; fi

Fair question - the answer is 'No, your simpler alternative does not do the same thing'.

Suppose I write this before your test:

VAR=

Your test will say "VAR is not set at all", but mine will say (by implication because it echoes nothing) "VAR is set but its value might be empty". Try this script:

(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo "JL:1 VAR is not set at all"; fi
if [ -z "${VAR}" ];     then echo "MP:1 VAR is not set at all"; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo "JL:2 VAR is not set at all"; fi
if [ -z "${VAR}" ];     then echo "MP:2 VAR is not set at all"; fi
)

The output is:

JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all

In the second pair of tests, the variable is set, but it is set to the empty value. This is the distinction that the ${VAR=value} and ${VAR:=value} notations make. Ditto for ${VAR-value} and ${VAR:-value}, and ${VAR+value} and ${VAR:+value}, and so on.


As Gili points out in his answer, if you run bash with the set -o nounset option, then the basic answer above fails with unbound variable. It is easily remedied:

if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi

Or you could cancel the set -o nounset option with set +u (set -u being equivalent to set -o nounset).

2 of 12
44
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~> 

-z works for undefined variables too. To distinguish between an undefined and a defined you'd use the things listed here or, with clearer explanations, here.

Cleanest way is using expansion like in these examples. To get all your options check the Parameter Expansion section of the manual.

Alternate word:

~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED

Default value:

~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED

Of course you'd use one of these differently, putting the value you want instead of 'default value' and using the expansion directly, if appropriate.

Top answer
1 of 3
12

Use parameter expansion:

: ${var:?}

Remove the colon if the empty string is a valid value (i.e., you only want to test for definedness).

: ${var?}

If you don't want the script to stop on the problem, you can use

if [[ ${var:+1} ]] ; then
    # OK...
else
    echo Variable empty or not defined. >&2
fi

Documented under Parameter Expansion in man bash:

When not performing substring expansion, using the forms documented below (e.g., :-), bash tests for a parameter that is unset or null. Omitting the colon results in a test only for a parameter that is unset.

${parameter:?word}

Display Error if Null or Unset. If parameter is null or unset, 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}

Use Alternate Value. If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.

2 of 3
9

You probably want to use indirect expansion: ${!variable} and then -n to check if it has been defined:

The indirect expansion consists in calling a variable with another variable. That is, as the variable name may be changing, instead of saying $a we say ${!var} and var=a.

$ cat a
var1_ID=0x04
var2_ID=0x05
var3_ID=0x06
var4_ID=0x09

for i in {1..5}; do
   v="var${i}_ID"
   if [ -n "${!v}" ]; then             # <-- this expands to varX_ID
      echo "$v set to value: ${!v}"
   else
      echo "$v not set"
   fi
done

If we execute, we get:

$ ./a
var1_ID set to value: 0x04
var2_ID set to value: 0x05
var3_ID set to value: 0x06
var4_ID set to value: 0x09
var5_ID not set

From man test:

-n STRING

the length of STRING is nonzero

🌐
Tiloid
tiloid.com › p › checking-if-a-variable-is-set-in-bash
Checking if a variable is set - Tiloid
July 25, 2023 - # Declare the variable variable="Hello" # Check if the variable is set if [[ -n "$variable" ]]; then echo "Variable is set." fi · The [[ ]] approach works similarly to the test command but offers better readability and additional features.
🌐
iO Flood
ioflood.com › blog › bash-check-if-environment-variable-is-set
How-To Check if a Bash Environment Variable is Set
November 27, 2023 - They allow you to check if a variable is set without considering its value. However, they might be less readable to someone unfamiliar with these commands. As always, the best method depends on your specific needs. If readability is a priority, you might prefer the ‘-z’ and ‘-n’ operators. If you need more control, the ‘isset’ command or the ‘[[ -v VAR ]]’ test might be better choices. When working with environment variables in Bash, you might encounter some common issues.
🌐
LinuxSimply
linuxsimply.com › home › bash scripting tutorial › bash variables › variable declaration and assignment › how to check variable value using bash scripts? [5 cases]
How to Check Variable Value Using Bash Scripts? [5 Cases] - LinuxSimply
January 4, 2024 - In Bash scripting, you can check if a variable is defined (whether it has been assigned a value). You can pass the -z option to the if command or conditional expression to check the variable.
🌐
Baeldung
baeldung.com › home › scripting › check if a variable exists in a list in bash
Check if a Variable Exists in a List in Bash | Baeldung on Linux
March 25, 2025 - To do this, we’ll learn to iterate over the list using for, to use grep, and to use regular expressions with Bash’s [[ ]]. Let’s start with a list of fruits called list_of_fruits: $ list_of_fruits="banana pear apple strawberry lime" In this case, we are using whitespaces as items delimiters. However, we can choose any character as a delimiter. Now, we want to check if a variable exists in the list or not. Let’s suppose there is a function called exists_in_list that checks if an element exists in a list or not.
Top answer
1 of 3
44

Portable to all POSIX shells:

if [ -n "${foobar+1}" ]; then
  echo "foobar is defined"
else
  echo "foobar is not defined"
fi

Make that ${foobar:+1} if you want to treat foobar the same way whether it is empty or not defined. You can also use ${foobar-} to get an empty string when foobar is undefined and the value of foobar otherwise (or put any other default value after the -).

In ksh, if foobar is declared but not defined, as in typeset -a foobar, then ${foobar+1} expands to the empty string.

Zsh doesn't have variables that are declared but not set: typeset -a foobar creates an empty array.

In bash, arrays behave in a different and surprising way. ${a+1} only expands to 1 if a is a non-empty array, e.g.

typeset -a a; echo ${a+1}    # prints nothing
e=(); echo ${e+1}            # prints nothing!
f=(''); echo ${f+1}          # prints 1

The same principle applies to associative arrays: array variables are treated as defined if they have a non-empty set of indices.

A different, bash-specific way of testing whether a variable of any type has been defined is to check whether it's listed in ${!PREFIX*}. This reports empty arrays as defined, unlike ${foobar+1}, but reports declared-but-unassigned variables (unset foobar; typeset -a foobar) as undefined.

case " ${!foobar*} " in
  *" foobar "*) echo "foobar is defined";;
  *) echo "foobar is not defined";;
esac

This is equivalent to testing the return value of typeset -p foobar or declare -p foobar, except that typeset -p foobar fails on declared-but-unassigned variables.

In bash, like in ksh, set -o nounset; typeset -a foobar; echo $foobar triggers an error in the attempt to expand the undefined variable foobar. Unlike in ksh, set -o nounset; foobar=(); echo $foobar (or echo "${foobar[@]}") also triggers an error.

Note that in all situations described here, ${foobar+1} expands to the empty string if and only if $foobar would cause an error under set -o nounset.

2 of 3
7

To sum up with Gilles' answer I made up my following rules:

  1. Use [[ -v foobar ]] for variables in Bash version >= 4.2.
  2. Use declare -p foobar &>/dev/null for array variables in Bash version < 4.2.
  3. Use (( ${foo[0]+1} )) or (( ${bar[foo]+1} )) for subscripts of indexed (-a) and keyed (-A) arrays (declare), respectively. Options 1 and 2 don't work here.
🌐
Linux Hint
linuxhint.com › check_variable_set_bash
How to check the variable is set or empty in bash – Linux Hint
Many times it requires to know the particular variable is set or not for the programming purposes. One of the important purposes of checking the variable is set or not is data validation. Bash has no built-in function like other standard programming languages to check a variable is set or not.