Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test for a Bash variable being unset, using a function

A simple Bash variable test goes:

${varName:?    "${varName} is not defined"} 

I'd like to reuse this, by putting it in a function. How can I do it?

The following fails

# # Test a variable exists tvar(){  val=${1:?    "${1}    must be defined, preferably in $basedir"}  if [ -z ${val}  ]      then      echo Zero length value  else      echo ${1} exists, value ${1}  fi } 

I.e., I need to exit if the test fails.

like image 384
DaveP Avatar asked May 17 '09 11:05

DaveP


People also ask

How can you determine if a bash variable is unset?

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

How do you check if a variable is not set?

'-v' or '-z' option is used to check the variable is set or unset. The above Boolean expression will return true if the variable is set and returns false if the variable is not set or empty.

How do I check if a variable is undefined in shell script?

Here is what I think is a much clearer way to check if a variable is defined: var_defined() { local var_name=$1 set | grep "^${var_name}=" 1>/dev/null return $? }

How do I test a variable in bash?

To check if a variable is set in Bash Scripting, use-v var or-z ${var} as an expression with if command. This checking of whether a variable is already set or not, is helpful when you have multiple script files, and the functionality of a script file depends on the variables set in the previously run scripts, etc.


2 Answers

Thanks to lhunath's answer, I was led to a part of the Bash man page that I've overlooked hundreds of times:

     When  not performing substring  expansion, bash tests for a parameter that     is unset  or null; omitting the colon results in a test only for a parame‐     ter that is unset. 

This prompted me to create the following truth table:

                  | unset |   set    | set and  | meaning                 |       | but null | not null |     ============+=======+==========+==========+=============================      ${var-_}   |   T   |     F    |    T     | not null or not set     ------------+-------+----------+----------+-----------------------------      ${var:-_}  |   T   |     T    |    T     | always true, use for subst.     ------------+-------+----------+----------+-----------------------------      $var       |   F   |     F    |    T     | var is set and not null     ------------+-------+----------+----------+-----------------------------      ${!var[@]} |   F   |     T    |    T     | var is set  

This table introduces the specification in the last row. The Bash man page says "If name is not an array, expands to 0 if name is set and null otherwise." For purposes of this truth table, it behaves the same even if it's an array.

like image 191
Dennis Williamson Avatar answered Oct 31 '22 04:10

Dennis Williamson


What you're looking for is indirection.

assertNotEmpty() {     : "${!1:? "$1 is empty, aborting."}" } 

That causes the script to abort with an error message if you do something like this:

$ foo="" $ assertNotEmpty foo bash: !1:  foo is empty, aborting. 

If you just want to test whether foo is empty, instead of aborting the script, use this instead of a function:

[[ $foo ]] 

For example:

until read -p "What is your name? " name && [[ $name ]]; do     echo "You didn't enter your name.  Please, try again." >&2 done 

Also, note that there is a very important difference between an empty and an unset parameter. You should take care not to confuse these terms! An empty parameter is one that is set but just set to an empty string. An unset parameter is one that doesn't exist at all.

The previous examples all test for empty parameters. If you want to test for unset parameters and consider all set parameters OK, whether they're empty or not, use this:

[[ ! $foo && ${foo-_} ]] 

Use it in a function like this:

assertIsSet() {     [[ ! ${!1} && ${!1-_} ]] && {         echo "$1 is not set, aborting." >&2         exit 1     } } 

Which only aborts the script when the parameter name you pass denotes a parameter that isn't set:

$ ( foo="blah"; assertIsSet foo; echo "Still running." ) Still running. $ ( foo=""; assertIsSet foo; echo "Still running." ) Still running. $ ( unset foo; assertIsSet foo; echo "Still running." ) foo is not set, aborting. 
like image 35
lhunath Avatar answered Oct 31 '22 04:10

lhunath