skip to Main Content

Ubuntu 22.04.2 LTS
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)

My Task

I want to test in a generic way if var is set and not empty.

The script

#!/bin/bash

set -e
set -u
set -o pipefail

if [ $# -ne 1 ] ; then
    echo "num: $#"
    echo "Usage: $0 <VAR_NAME>"
    exit 1
fi
varname=$1

cmd="if [ -z "$$varname" ]; then echo "$varname is blank or unset"; else echo "$varname is set to '$$varname'"; fi"

echo "$cmd"
eval "$cmd"

this script a based on that site:

How to check if a variable is set in Bash

The actual behaviour 1 (it does not work)

if you execute your statement like

bla=3
./trv_test_var.sh "bla"

you receive the following response:

if [ -z "$bla}" ]; then echo "bla is blank or unset"; else echo "bla is set to '$bla'"; fi
./trv_test_var.sh: line 19: bla: unbound variable

but if you exceute the outputed command it works as expected:

if [ -z "$bla" ]; then echo "bla is blank or unset"; else echo "bla is set to '$bla'"; fi
bla is set to '3'

The actual behaviour 2 (it works but wrongly)

First of all please change the line 14 with the followin code:

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

Now:

bla=3
./trv_test_var.sh "bla"

you receive:

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

but if you exceute the outputed command it works as expected:

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

The desired behaviour:

I execute the statement with

cmd="if [ -z "$$varname" ]; then echo "$varname is blank or unset"; else echo "$varname is set to '$$varname'"; fi"

and it shows me if the var set or not.

Please help.

2

Answers


  1. This should work :

    cmd="if [ -z "$varname" ]; then echo "varname is blank or unset"; else echo "varname is set to '$varname'"; fi"
    

    As said others, try to avoid using eval and putting commands in strings.

    Login or Signup to reply.
  2. Your approach is difficult. eval is not needed and not that easy to make it work.

    But there is a better and much simpler solution. It relies on the indirection functionality offered by Bash in parameter expansion. The manual says:

    The basic form of parameter expansion is ${parameter}. The value of parameter is substituted.

    If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of indirection. Bash uses the value formed by expanding the rest of parameter as the new parameter; this is then expanded and that value is used in the rest of the expansion, rather than the expansion of the original parameter. This is known as indirect expansion.

    Your code can be as simple as:

    isset() {
      local varname=$1
    
      if [ -n "${!varname}" ]; then
        echo "Variable '$varname' is set"
      else
        echo "Variable '$varname' is empty or not set"
      fi
    }
    
    FOO=bar
    
    isset FOO
    isset BAR
    

    You can write a function or a script, the code is the same (the body of the function listed above).

    Check it online.

    Update

    It can be done even more simple, without indirection. Use -v and do not expand the variable that you want to check. Expand only the parameter to find the name of the variable to check:

    isset() {
      local varname=$1
    
      if [ -v "$varname" ]; then
        echo "Variable '$varname' is set"
      else
        echo "Variable '$varname' is empty or not set"
      fi
    }
    
    FOO=bar
    
    isset FOO
    isset BAR
    

    Check it online.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search