8

I have to execute a function which has to test if a variable has been correctly defined in Bash and must use its associated value.

For instance, these variables are initialized at the top of the script.

#!/bin/bash

var1_ID=0x04
var2_ID=0x05
var3_ID=0x06
var4_ID=0x09

I would like to call the script named test as follows:

./test var1

The current implemented function is:

function Get()
{
     if [ $1"_ID" != "" ]; then
         echo "here"
         echo $(($1_ID))
     else
         exit 0
     fi
}

I don't understand why I obtain here even if I enter ./test toto or something else.

Do I need to use a specific command, such as grep?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ogs
  • 1,139
  • 8
  • 19
  • 42
  • Related: [How to test if a variable is defined at all in Bash prior to version 4.2 with the nounset shell option?](http://unix.stackexchange.com/a/56846/40596) – fedorqui Nov 24 '14 at 15:20
  • 3
    It seems no one has stated this, but `$1"_ID"` will evaluate to `"_ID"` if `$1` doesn't exist. And therefore will ALWAYS be `!= to ""` – Tom Myddeltyn Jan 23 '17 at 15:58

3 Answers3

12

Use parameter expansion:

: ${var:?}

Remove the colon if the empty string is a valid value (i.e., you only want to test for definedness).

: ${var?}

If you don't want the script to stop on the problem, you can use

if [[ ${var:+1} ]] ; then
    # OK...
else
    echo Variable empty or not defined. >&2
fi

Documented under Parameter Expansion in man bash:

When not performing substring expansion, using the forms documented below (e.g., :-), bash tests for a parameter that is unset or null. Omitting the colon results in a test only for a parameter that is unset.

${parameter:?word}

Display Error if Null or Unset. If parameter is null or unset, the expansion of word (or a message to that effect if word is not present) is written to the standard error and the shell, if it is not interactive, exits. Otherwise, the value of parameter is substituted.

${parameter:+word}

Use Alternate Value. If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.

choroba
  • 231,213
  • 25
  • 204
  • 289
9

You probably want to use indirect expansion: ${!variable} and then -n to check if it has been defined:

The indirect expansion consists in calling a variable with another variable. That is, as the variable name may be changing, instead of saying $a we say ${!var} and var=a.

$ cat a
var1_ID=0x04
var2_ID=0x05
var3_ID=0x06
var4_ID=0x09

for i in {1..5}; do
   v="var${i}_ID"
   if [ -n "${!v}" ]; then             # <-- this expands to varX_ID
      echo "$v set to value: ${!v}"
   else
      echo "$v not set"
   fi
done

If we execute, we get:

$ ./a
var1_ID set to value: 0x04
var2_ID set to value: 0x05
var3_ID set to value: 0x06
var4_ID set to value: 0x09
var5_ID not set

From man test:

-n STRING

the length of STRING is nonzero

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • 1
    Thank you fedorqui. However, I am not sur to understand. What means ${!v} ? – ogs Nov 24 '14 at 15:30
  • This is called **indirect expansion**. It consists in calling a variable with another variable. That is, as the variable name may be changing, instead of saying `$a` we say `${!var}` and `var=a`. You can read more in [bash: indirect expansion, please explain?](http://stackoverflow.com/q/8515411/1983854). – fedorqui Nov 24 '14 at 16:02
  • 1
    And, as fedorqui pointed out via [a related article](http://unix.stackexchange.com/a/56846/40596), you can test for whether something is _set_ using the expansion `${variable+string}`. – Ray Nov 24 '14 at 19:31
3

In bash 4.2, you can use the -v operator in a conditional expression to test if a variable with the given name is set.

if [[ -v ${1}_ID ]]; then
    echo "${1}_ID is set"
    foo=${1}_ID
    echo "${!foo}"
fi

You still need indirect parameter expansion to get the value.

In bash 4.3 you can use a named reference to make working with it easier.

declare -n param=${1}_ID
if [[ -v param ]]; then
    echo "${1}_ID"
    echo "$param"
fi

(param will behave exactly like the variable it references. I don't know if there is an easy way, short of parsing the output of declare -p param, to get the name of the variable it references.)

chepner
  • 497,756
  • 71
  • 530
  • 681
  • What is "`_ID`"? A convention? A magic value? Perhaps explain it in the answer? – Peter Mortensen Mar 01 '22 at 17:10
  • It's just the constant portion of the variable names that the OP is using. The assumption is that `$1` has a value like `var1`, `var2`, etc. `var1` and `_ID` together forms `var1_ID`, and that's the name of the variable whose existence we are testing for. – chepner Mar 01 '22 at 17:12