3

When trying to check if a variable is set or unset in bash, I found the bash conditional expression: -v (here: True if the shell variable is set (has been assigned a value).). I try the code:

#!/bin/bash
VAR="not-empty"
if [ ! -v "$VAR" ]; then
        echo "unset"
else 
        echo "set: $VAR"
fi

But, the output is unset even i assigned VAR at the begin of code.

I found How to check if a variable is set in Bash? question, and tried to replace ! -v by -z to check the string variable VAR. The output is set: non-empty.

Anyone can help to explain the first case (using -v expression) why the output is unset?

My bash version:

GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu) Copyright (C) 2019 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html

Hitokiri
  • 3,607
  • 1
  • 9
  • 29

2 Answers2

4

You don't need the $ when checking if it is set and so:

if [[ ! -v VAR ]]; then
    echo "unset"
else 
    echo "set: $VAR"
fi
Raman Sailopal
  • 12,320
  • 2
  • 11
  • 18
  • Can you explain why it works when we don't use `$` ? – Hitokiri Jan 13 '21 at 16:04
  • 1
    $ normally expands a variable or command. In this instance, we are not expanding. – Raman Sailopal Jan 13 '21 at 16:05
  • 4
    It's not that you can't use `$`, but that the argument to `-v` is supposed to take the name of a variable as its argument. If you want to check if `VAR` is set, then `VAR`, not the expansion of `$VAR`, is the argument you want. – chepner Jan 13 '21 at 16:30
1

Checking the manual for bash, I found:

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

But the problem is:

VAR="not-empty"
[ ! -v "$VAR" ]

is not incorrect, but performs a different test. It checks if there is a variable named 'not-empty' that is set.

You should test like this:

#!/bin/bash
VAR="not-empty"
if [ ! -v VAR ]; then
        echo "unset"
else 
        echo "set: $VAR"
fi
Wolbec
  • 46
  • 4
  • 2
    This is a better answer, *except* that it's using `[` instead of `[[`. When you _absolutely require_ that a shell-builtin `test` implementation be used and are targeting a ksh-family shell such as bash, `[[` is the better choice: Even though modern shells _do_ generally have built-in `[` implementations, that's generally a performance enhancement and the only standard-guaranteed behaviors are those specified for `/usr/bin/[`, which (as an external command) can't see shell variables and [isn't specified](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html) to have a `-v`. – Charles Duffy Jan 13 '21 at 16:25