2

I need to be able to check if a variety of similar variables are set in bash.

I need to check if the string defined in the variable CONFIG_STRING_TO_CHECK has been set.

I would like to do something like this:

#!/bin/bash

CUSTOM_PREFIX='custom1'

# Common Variable Name Endings:
CONFIG_STRINGS=( "config1" "config2" )

# Loop over common variable endings
for CONFIG_STRING in "${CONFIG_STRINGS[@]}" do :

  # Set the variable name to check
  CONFIG_STRING_TO_CHECK="${CUSTOM_PREFIX}_$CONFIG_STRING"

  # Check if variable is defined
  if [ -z ${CONFIG_STRING_TO_CHECK+x} ]; then
    echo "$CONFIG_STRING_TO_CHECK is declared";
  else
    echo "$CONFIG_STRING_TO_CHECK is not declared"; 
    exit 1;
  fi

done

After some Googling I found this answer, but it doesn't work. I think it's because this is checking if the variable CONFIG_STRING_TO_CHECK is set... which it always is.

Just to be clear, I would like this to check if the following strings are set:

custom1_config1
custom1_config2

Not:

CONFIG_STRING_TO_CHECK

I hope this makes sense. Pease help.

Community
  • 1
  • 1
Steven Leimberg
  • 775
  • 1
  • 4
  • 17

2 Answers2

6

Use indirect expansion (!), as follows:

~> A=a
~> B=b
~> a_b=c
~> A_B=${A}_${B}
~> echo ${!A_B}
c

Note that you have to have an intermediate variable name to do this -- you can't do echo ${!${A}_${B}}. see man bash for more details:

If the first character of parameter is an exclamation point (!), it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. The exceptions to this are the expansions of ${!prefix*} and ${!name[@]} described below. The exclamation point must immediately follow the left brace in order to introduce indirection.


EDIT: I just tried with this, and it seems to work:

# !/bin/bash

CUSTOM_PREFIX='custom1'

custom1_config1="hi"
#custom1_config2="there"

# Common Variable Name Endings:
CONFIG_STRINGS=( "config1" "config2" )

# Loop over common variable endings
for CONFIG_STRING in "${CONFIG_STRINGS[@]}"; do
        CONFIG_STRING_TO_CHECK="${CUSTOM_PREFIX}_${CONFIG_STRING}"
        if [ -z ${!CONFIG_STRING_TO_CHECK} ]; then
                echo ${CONFIG_STRING_TO_CHECK} is not defined
        else
                echo ${CONFIG_STRING_TO_CHECK} is ${!CONFIG_STRING_TO_CHECK}
        fi
done

and got:

~/tmp/tst3> ./tmp.sh  
custom1_config1 is hi
custom1_config2 is not defined
John
  • 2,910
  • 2
  • 23
  • 41
  • Sorry, for whatever reason this wasn't working for me. I did as you said and used an intermediate variable, but it always returned true. – Steven Leimberg Mar 15 '16 at 14:38
  • Odd... I just tried cutting and pasting your example, (fixed the for do line), and added my changes. It seemed to work fine on my machine.. I'll paste my code in my answer -- should work on all versions of bash that I know of... – John Mar 15 '16 at 15:39
  • Ahhh I see. After fixing my "for do" statement this also worked for me. I have marked your answer as the accepted answer since you technically posted first. Thanks John! – Steven Leimberg Mar 15 '16 at 16:41
3

The declare builtin can show you, using the -p option.

$ var=PATH
$ if declare -p "$var" &>/dev/null; then echo "$var is declared"; fi
PATH is declared
$ var=FOOBAR
$ if declare -p "$var" &>/dev/null; then echo "$var is declared"; else echo "$var is not declared"; fi
FOOBAR is not declared

Additionally, this can be encapsulated into a function:

$ is_declared() { declare -p "$1" &>/dev/null; }
$ if is_declared PATH; then echo OK; else echo NO; fi
OK
$ is_declared FOOBAR && echo OK || echo NO
NO

It works with variables declared locally to a function as well

$ test_func() { local localvar=42; is_declared localvar && echo OK || echo NO; }
$ test_func
OK
glenn jackman
  • 207,528
  • 33
  • 187
  • 305
  • Technically John posted first and his solution did work after further discovery. Yours worked first try regardless of the fact that my for do command apparently wasn't properly written. I'm giving John the accepted answer credit, but I did mark your answer as useful. Thank you. – Steven Leimberg Mar 15 '16 at 16:41