Bash Shell Find Out If a Variable Is Empty Or Not

My shell script depends upon user input. How do I find out if a variable called $_JAIL path is empty under a Linux / Apple OS X / Unix like operating systems? Can you tell me command on bash shell to find out if a variable is empty?

Tutorial details
Difficulty Easy (rss)
Root privileges No
Requirements Linux or Unix with bash
Time 5m
You can pass the -z option to the if command or conditional expression. If the length of STRING is zero, variable ($var) is empty. The test command is used to check file types and compare values. This page shows how to find out if a bash shell variable is empty or not using the test command.

Fig.01: Bash scripting various way to determine if a variable is empty

To find out if a bash variable is empty:

  1. Return true if a bash variable is unset or set to the empty string: if [ -z "$var" ];
  2. Another option: [ -z "$var" ] && echo "Empty"
  3. Determine if a bash variable is empty: [[ ! -z "$var" ]] && echo "Not empty" || echo "Empty"

Bash Shell Find Out If a Variable Is Empty Or Not

Let us see syntax and examples in details. The syntax is as follows for if command:

if [ -z "$var" ]
      echo "\$var is empty"
      echo "\$var is NOT empty"


if test -z "$var" 
      echo "\$var is empty"
      echo "\$var is NOT empty"

Another option to check if bash shell variable is empty or not

You can also try the control operators. The syntax is:

[ -z "$var" ] && echo "Empty"
[ -z "$var" ] && echo "Empty" || echo "Not empty"


[[ -z "$var" ]] && echo "Empty"
[[ -z "$var" ]] && echo "Empty" || echo "Not empty"


## Check if $var is set using ! i.e. check if expr is false ##
[ ! -z "$var" ] || echo "Empty"
[ ! -z "$var" ] && echo "Not empty" || echo "Empty"
[[ ! -z "$var" ]] || echo "Empty"
[[ ! -z "$var" ]] && echo "Not empty" || echo "Empty"

For example:

## taken from gen_html_to_pdf() ##
  set -- $line
  local pdfid="$1"
  local pdfurl="$2"
  local pdftitle="$3"
  local pdf="${output}/${pdfid}.pdf"
  [[ -z "$pdfurl" ]] && { echo "Error: URL not found in $_db"; exit 1; }
  echo "Creating $pdf ..."
  # rest of code ...

Sh/Bash one liner examples to determine if a bash variable is empty

Type the following command

## set _JAIL
## find out if it is empty or not ##
[  -z "$_JAIL" ] && echo "Empty: Yes" || echo "Empty: No"

Another example:

[  -z "$_JAIL" ] && echo "Empty: Yes" || echo "Empty: No"

Another example:

## unset (remove) $_JAIL ##
unset _JAIL
[  -z "$_JAIL" ] && echo "Empty: Yes" || echo "Empty: No"

if command syntax and example

if [ -z "$_JAIL" ] 
	echo "Please set \$_JAIL"
	echo "Setting up jail at $_JAIL"
        //call setjail()
        // setjail

A note about double bracket syntax

If portability is not your concern try:

## set _JAIL
## find out if it is empty or not ##
[[ -z "$_JAIL" ]] && echo "Empty" || echo "Not empty"</kbd>


### Warning: Portability issue. ###
## note double bracket syntax:
if [[ -z "$_JAIL" ]]
	echo "Please set \$_JAIL"
	echo "Setting up jail at $_JAIL"
        //call setjail()
        // setjail

Example: Determine if a bash variable is empty

Finally here is a script to demonstrate the various possibilities with bash/sh/posix based shell:

# Do three possibilities for $JAIL ##
for i in 1 2 3 
case $i in
	1) JAIL="/nginx/jail"; HINT="value set";;
	2) JAIL=""; HINT="value set to empty string";;
	3) unset JAIL; HINT="\$JAIL unset";;
# Update user with actual values and action  
# $JAIL set to a non-empty string (1)
# $JAIL set to the empty string  (2)
# $JAIL can be unset (3)
echo "*** Current value of \$JAIL is '$JAIL' ($HINT) ***"
## Determine if a bash variable is empty or not ##
if [ -z "${JAIL}" ]; then
    echo "JAIL is unset or set to the empty string"
if [ -z "${JAIL+set}" ]; then
    echo "JAIL is unset"
if [ -z "${JAIL-unset}" ]; then
    echo "JAIL is set to the empty string"
if [ -n "${JAIL}" ]; then
    echo "JAIL is set to a non-empty string"
if [ -n "${JAIL+set}" ]; then
    echo "JAIL is set, possibly to the empty string"
if [ -n "${JAIL-unset}" ]; then
    echo "JAIL is either unset or set to a non-empty string"

Sample outputs from Bash version 3.2.51:

Fig. 01: Test the various possibilities of variable


You just learned how to determine if a bash variable is empty using various methods. It is easy to find whether or not a variable is empty in Bash under Linux or Unix-like system when you use the following syntax:

## syntax 1 ##
if [[ -z "$variable" ]]; then
   echo "Empty $variable"
   echo "Do whatever you want as \$variable is not empty"
## Syntax 2 ##
[[ -z "$variable" ]] && echo "Empty" || echo "Not empty"
## Syntax 3 ##
[  -z "$var" ] && echo "Empty: Yes" || echo "Empty: No"

I suggest that you read the following resources for more info or see GNU/bash man page here:

🐧 Please support my work on Patreon or with a donation.
🐧 Get the latest tutorials on Linux, Open Source & DevOps via:
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
22 comments… add one
  • Mike Steele Dec 7, 2012 @ 3:32

    There are a number of advantages of using double brackets for conditionals. One of my favorites is that you do NOT need to use quotes around a variable. It doesn’t matter if it’s empty, has spaces/tabs/newlines in it. You don’t need the quotes.

  • Chris F.A. Johnson Dec 7, 2012 @ 5:37

    [ -n “$var” ] || echo EMPTY

    • c0t0r Nov 24, 2013 @ 11:22

      yes, that’s right

  • Shantanu Gadgil Dec 7, 2012 @ 6:35


    AFAIK ,the ‘double square brackets’ is bashism and would not work in ‘sh’

    The above could be working if ‘sh’ is symlinked to ‘bash’ ?!?

    • Mike Steele Dec 7, 2012 @ 7:17

      Double brackets were introduced by David Korn in ksh in the early 80s. Bash was introduced in the late 80’s as an open source shell and incorporated nearly all the features of ksh. I don’t think there are any nix’s that don’t have bash or ksh. I last did serious work on Unix around 2001 till I was forced by circumstances to switch to Linux. I’ve used double brackets since the early 90’s and never had a problem. On many of the Linux system’s I’ve worked on, sh was a symlink to bash. When bash is started as “sh”, it behaves differently (sort of brain dead), but I think it still supports the double bracket. It’s hard to know, since by convention, shell scripts have the “shebang” as the first line (#!/bin/bash).

      • Shantanu Gadgil Dec 10, 2012 @ 13:38

        By ‘bashism’ I meant “it is not ‘sh’ syntax”. It would mostly work on “advanced” ‘sh’ compliant shells.

        As you can see, in the second example, the interpreter is marked as “bin/sh” and the file contains “double square brackets” syntax, which could fail on so many different oses.

        Many non-Linux nixes have only sh (which may or may not be some variant of ksh on solaris, others, I dunno). My recent installation of PCBSD has only csh installed by default. (yuck!)
        Many-a-times, AIX installations do not have bash/ksh/whatever by default. Only sh is installed.

        All I was saying was … the sentence should clearly state why the “double-square-bracket” syntax could fail, rather than just mentioning “portability”.

        *** I know how to install bash on all the platforms, discussing that is not necessary.

        • 🐧 nixCraft Dec 10, 2012 @ 16:39

          The example in question has been updated.

  • emi2fast Dec 7, 2012 @ 8:14

    [[ $N ]] || echo “Empty”

  • Chris F.A. Johnson Dec 7, 2012 @ 8:28

    When bash is started as sh, the only difference is in which startup files it reads. Its features are unchanged.

    The shebang is unnecessary unless the script uses syntax that the default shell doesn’t understand. And if you use a non-standard shell, you can’t be sure where it is. I use systems where bash is either /bin/bash, /usr/bin/bash, /usr/local/bin/bash or /usr/xpg4/bin/bash. You may be safe with “#!/usr/bin/env bash” but I have used systems where env is in /bin, not /usr/bin.

    I don’t use double brackets. The only thing they give that you can’t do without them is comparing a string against a regular expression (and I have very little need for that).

  • Mike Steele Dec 7, 2012 @ 17:45

    The shebang saves a bit of time. (It tells the shell what to use to run the program. Otherwise, it has to figure it out. It forks itself as the last resort.) I’ve been using Linux almost exclusively for the last ten or so years, but have occasionally used other ‘nix’s (most recently AIX). I’ve not had a problem with the location of bash.

    There are several reasons Korn added double bracket. If you remember your history, the original condition checker was “test”, located in /bin. Then came “[…]”. Actually ‘[‘ was a hard link to /bin/test. After a while, these were converted to built-ins, but due to backward compatiblity requirements, no advantage could be taken of this (other than improved performance).

    Korn introduced double brackets to get around the backward-compatibility requirement. The problem with single bracket is that all the command line parsing is completed before the condition is tested. That’s why quotes are often necessary.

    If you use “type [” you will see “[ is a shell builtin”. Builtins act like programs. If you use “type [[“, you will see “[[ is a shell keyword”. The difference is that the shell sees the keyword and knows what’s going on. It knows that $var is a variable. And that’s why variables need not be quoted. Ever. Further, double bracket knows what “||” and “&&” are. So, you don’t need to use “-o” and “-a”. Example:
    [[ -f $File && -r $File ]] || echo “‘Not a readable file: ‘$File'”

    Finally, as noted before, you can compare strings (or variable) to shell patterns (not regular expressions). This can be truly useful. For example:
    [[ $S3Msg = ERROR:* ]] && S3Stat=1

    A friendly vendor gave me “The Korn Shell” by David Korn in the early nineties. I’ve been forever grateful. I’ve adopted all the new features, and (due to other things), got as much as a 200 times performance improvement over the old Bourne Shell. When I was forced to move to bash (because pdksh was so buggy), I soon figured out that the minor incompatibilities in no way reduced the functionality of bash. I’ve learned to love it.

  • Chris F.A. Johnson Dec 7, 2012 @ 17:53

    You can compare strings or variables against a pattern without using double brackets;use a case statement:

    case $var in
       [a-m]*) echo "First half of alphabet" ;;
       [n-z]*) echo "second half of alphabet" ;;

    You don’t need double brackets to use && or || with test:

    if [ "$x" = 1 ] && [ "$y" = 2 ] || [ "$z" != 3 ]

    Having to quote variables is not a problem; not doing it leads to bad habits.

  • Mike Steele Dec 7, 2012 @ 18:03

    Using a case statement is a lot of trouble to avoid writing a compound conditional. And don’t get me started on case statements without the leading paren in the condition statements!

    The second form, where you put “&&” and “||” between the condition checks is actually worse than just using -a and -o. And to what purpose? Double bracket solves the problem!

    The comment on “bad habits” … what can I say? I’ve heard people say the same thing about always using braces in their variables: ${x}. If you know what you are doing, you know when braces are necessary. You know when quotes are necessary (or desireable). Certainly, you get different results between ‘echo $x’ and ‘echo “$x”‘. If you know what you are doing, you know which is correct for the situation.

  • Chris F.A. Johnson Dec 7, 2012 @ 18:11

    A case statement is no trouble and is much more flexible than [[ … ]]. And it’s portable; [[ … ]] is not.

    Why is && worse than -a?

    The use of -a and -o is deprecated in the POSIX standard.

  • Mike Steele Dec 8, 2012 @ 8:17

    That’s the point. Not only is a case statement no trouble (as you say), double bracket is even less than no trouble. We regard to portability, I’ve been doing shell programming since 85. There were a LOT of issues with Bourne Shell on all the different ‘nix’s that I worked with. (They were “compatible”. NOT!) They claimed to obey the same rules, but the rules were incomplete, and there were differences in limitations. For example, on Ultrix, you were limited to 20 levels of recursion — and that was a BEAR to debug! The solution(s) were to (a) try to figure out a subset of stuff that worked; and (b) try to find a shell on each flavor of Unix (MIPS, IBM, DEC, SCO, DG, NCR, ETC) that would always work (and to write some clever code that could determine what machine you were on and re-launch the script with that shell). I found ksh this way.

    Then this DG guy told me that ksh was now on all Unixes. And he gave me “The Korn Shell”. That was around 1993. I looked on all the machines in house (list above) and found that it was true. I read the book and wrote pages of notes on what could be done and how that would help. For example, I found that using ((Idx = 0; Idx < $X; Idx++)) was roughly 200 times faster than using "Idx=`expr $Idx + 1`" in a loop and then testing $Idx -ge $X.

    So, just how "non-portable" is double bracket? It's portable. With an exception. At some point I ran into a Linux that uses "dash" to run the startup scripts. Dash is a minimal shell, but it's very fast. If you write anything that will execute on startup, you should take the precaution of putting the shebang in the first line. (Should always be there anyway … ya never know when someone will launch your script with zsh or some other odd duck. It's faster, too.)

    I found that the pattern matching ability of double-bracket was roughly 200 times faster than echoing a variable through grep and testing the result.

    I found that "$(< file)" was roughly 200 times faster than `cat file`. And I found a great deal of advantage in being able to nest $(…). (You can nest backticks, but you have to backslash 'em.) This, by the way, is why Korn introduced leading (left) parens in the condition tests of case statements. It let you embed case statements in $(…) command line substitutions. That is, it lets you keep your parens balanced.

    You asked why "&&" is worse than -a. It's all context. With double brackets, you use "&&" and "||" to express a compound condition. With single brackets, you use "-a" and "-o" for the same purpose. It can be a bit trickier, because the shell interprets the line before the condition check takes place. Regardless, these are equivalents.

    Where I said "&&" is worse than -a, I was pointing out that the example was avoiding compound conditionals by making the simple conditionals and using "&&"/"||" between them.

    I don't read posix standard. That's because I'm the victim here. I use what the gods give me. I'm gonna guess, however, that -a and -o are deprecated because double bracket is the standard.

  • Chris F.A. Johnson Dec 8, 2012 @ 8:34

    “Portable” means complying with the POSIX standard.

    The Bourne shell could not be counted on to be the same on all systems; the POSIX shell can.

    [[ … ]] cannot be counted on; [ … ] can, and is (with help from case) adequate for almost all needs.

    And, no, -a and -o are not deprecated because [[ … ]] is standard; it’s NOT. They are deprecated because they can lead to confusion and are not reliable in all cases. Where thare are more than 4 elements in a test expression, the result is undefined and cannot be depended on. Multiple tests separated by && or || always work.

    The double brackets are insignificantly faster than single brackets, nowhere near 200 times.

    Dash/ash is a POSIX shell; if you write POSIX-compliant scripts, they will run on dash — as well as ksh and bash.

  • Laaa Nov 24, 2013 @ 0:20

    [ -z “$var” ] || echo “Empty”

    there seems something wrong because this code says empty when it is not and outputs nothing if var is unset.

  • Chris F.A. Johnson Nov 24, 2013 @ 8:32

    [ -z “$var” ] succeeds if $var is empty.

    • Jared Wyatt Mar 12, 2014 @ 17:03


      The syntax examples at the top of this article are all backwards. They should be as follows:

      [ -z "$var" ] && echo "Empty"
      [[ -z "$var" ]] && echo "Empty"
      # Check if $var is set using ! i.e. check if expr is false ##
      [ ! -z "$var" ] || echo "Empty"
      [[ ! -z "$var" ]] || echo "Empty"

      Also, the one liner example is confusing and backwards. The following is correct:

      ## Is it empty?
      [ -z "$_JAIL" ] && echo "Yes" || echo "No"

  • nh Oct 12, 2020 @ 16:11

    small confusion in your examples or syntax.

    Some if conditions you have added ; and some or no ; after ].

    which one is valid (with/without ; )?

  • Richard Quadling Oct 15, 2020 @ 13:32

    How do you deal with string that contain both types of quotes?

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 @