How to check if bash variable defined in script

I need to set a bash environment variable called PURGEIMAGE and take specific actions in my script. For example, if PURGEIMAGE set, then purge images from CDN else just URL. I am going to call my script as PURGEIMAGE=yes ./ url1 url2. So how do I know if a bash variable set at the CLI and used in my bash script running on Linux or Unix-like systems?

We can pass the -z option to the if command or conditional expression to check if a bash variable defined in script or not.
Tutorial details
Difficulty Easy (rss)
Root privileges No
Requirements Bash running on Linux or Unix
Time 2m

To find out if a bash variable is defined:

  1. Return true if a bash variable is unset or set to the empty string: if [ -z ${my_variable+x} ];
  2. Also try: [ -z ${my_bash_var+y} ] && echo "\$my_bash_var not defined"
  3. Determine if a bash variable is set or not : [[ ! -z ${PURGEIMAGE+z} ]] && echo "Set" || echo "Not defined"
  4. Return true if the variable is set on Bash version 4.2+: [ -v $VAR ] && echo "Bash \$VAR NOT set"

if command syntax and example to see if bash variable named PURGEIMAGE set or not

The syntax is simple:

if [ -z ${PURGEIMAGE+x} ];
    echo "We need to only purge URL from Clodudfront CDN ..."
    echo "We need to purge images and URL from Cloudfront CDN ..."

OR use the test command

if test -z ${PURGEIMAGE+y}
    echo "We need to only purge URL from Clodudfront CDN ..."
    echo "We need to purge images and URL from Cloudfront CDN ..."

Then we run our script as
$ /path/to/script
$ PURGEIMAGE=whatever /path/to/script
# use the export command to export variable to sub-shells
$ export PURGEIMAGE=yes
$ /path/to/script

All exported variables can undefined values as follows using the unset command $ unset PURGEIMAGE
$ /path/to/script

How does ${my_variable+x} syntax works?

Let us print commands and their arguments as script is executed by using the set command:

set -x
PURGEIMAGE=whatever ./script
export PURGEIMAGE=whatever
set +x
  • The ${my_variable+x} is a bash parameter expansion.
  • It evaluates to nothing if my_variable is unset.
  • Otherwise it substitutes the string x.
  • You can use any string and not limited to x. For instance, I can use foobar as follows:
    # instead of 'x' we used 'foobar'
    # but 'x' seems like a good practice 
    if [ -z ${PURGEIMAGE+foobar} ];
        echo "We need to only purge URL from Clodudfront CDN ..."
        echo "We need to purge images and URL from Cloudfront CDN ..."

Another option to see if bash shell variable is set or not

We can try the control operators. The syntax is:

[ -z ${var+foo} ] && echo "\${var} not defined"
[ -z ${var+foo} ] && echo "\${var} not defined" || echo "\${var} is defined"

If portability is not your concern try [[ syntax

The following are bash specific option, and you need bash version 4.x+. I would avoid these examples due to portability issues if I were you, but I provide them below as they are in bash man pages.

[[ -z ${var+z} ]] && echo "\${var} not defined" 
[[ -z ${var+z} ]] && echo "\${var} not defined" || echo "\${var} is defined"

Checking if a variable is set in Bash or not

The -v VAR returns true if the shell variable VAR is set:

[[ -v ${var} ]] && echo "\${var} not defined" 
[[ -v ${var} ]] && echo "\${var} not defined" || echo "\${var} is defined"
[ -v ${var} ] && echo "\${var} not defined" || echo "\${var} is defined"

Putting it all together

## check bash variable defined or not ##
  if [  -z ${PURGEIMAGE+x} ]
     case "$u" in*) pattern="media/new/faq/";;
   *) pattern="/tips/wp-content/uploads/";;*) pattern="media/new/cms/";;
	     *) pattern="NULL"
     if [ "$pattern" != "NULL" ]
	     echo ' * Getting a list of images to purge from url ... '
	     wget -o /dev/null -O "$tmp_file" "$u"
	     if [ -f "$tmp_file" ]
		     img_urls="$img_urls $(grep -i 'img' "$tmp_file"  | grep -Po 'src="\K.*?(?=")' | grep "$pattern" | grep -E -v 'inbox-sign-up.002.jpeg')"
		     rm -f "$tmp_file"
     purge_images "$img_urls"
  purge_url "$u"

Summing up

CDN like Cloudfront and Cloudflare allows us to cache both images and HTML pages aggressively on the edge node. By caching those assets, we can speed up the website. However, when we updated pages, we need to remove URLs and images from the cache. However, often mages are not required to purge as we only update pages. This simple bash script allows me to purge assets as per our needs on-demand. See:

🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 4 comments so far... add one

CategoryList of Unix and Linux commands
File Managementcat
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network Utilitiesdig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
4 comments… add one
  • j Jan 29, 2021 @ 17:02

    Please explain how ${PURGEIMAGE+foobar}is different than ${PURGEIMAGE}? I thought you were trying to say if PURGEIMAGE was not defined is value would be set to foobar but that is not the case. Likewise, I am not seeing the difference in my test scripts if I remove +foobar?

    • 🐧 Vivek Gite Jan 29, 2021 @ 17:44


      [ -z ${var+y} ] && echo "Unset/Blank" || echo "Set"
      [ -z "$var" ] && echo "Unset/Blank" || echo "Set"
      [ -z ${var+y} ] && echo "Unset/Blank" || echo "Set"
      [ -z "$var" ] && echo "Unset/Blank" || echo "Set"
      unset var
      [ -z ${var+y} ] && echo "Unset/Blank" || echo "Set"
      [ -z "$var" ] && echo "Unset/Blank" || echo "Set"
  • Jay Patel Jan 30, 2021 @ 4:18

    Interesting, I like bash 4.2 solution. Very easy to use

    if [ -v ${var}  ];
  • Joe Klemmer Feb 2, 2021 @ 13:42

    It seems that -n works for this, too.

    if [ -n "$VAR" ]; then
        echo "Set"
        echo "Not set"

    At least it’s working for me.

Leave a Reply

Your email address will not be published. Required fields are marked *

Use HTML <pre>...</pre> for code samples. Problem posting comment? Email me @