Reputation: 653
The setup we currently have is to declare several variables in a config file and then we run some processes that depend on those variables. Additional functionality that I'm trying to provide is a default_variables script that will give default values to all the variables in the config files, while not overriding anything that is declared in the config file.
Here is my current code:
#!/bin/bash -x
# allows var to be used as an associative array
declare -A var
# variable declarations must be of the form:
# var[var_name]=var_value
# after processing loop, the above will be evaluated as:
# export var_name=var_value
# declare default variables
var[a]=a_val
var[b]=b_val
var[c]=c_val
var[d]=d_val
# iterate on associative array indices
for default_var in `echo "${!var[@]}"`
do
test_var=\$${default_var}
# only export variables that have not been previously declared
if [[ -z `eval $test_var` ]]
then
# export each index name as a variable
export $default_var=${var[$default_var]}
fi
done
The error I'm currently getting is that the eval statement tries to execute the value of a variable if it was declared before the script was ran. For instance, if the above script were ran twice then the error would be:
-sh: a_val: command not found
-sh: b_val: command not found
-sh: c_val: command not found
-sh: d_val: command not found
Now I am definitely up for a more elegant way of solving this problem, but this is the best I could come up with. Finally, I know that exporting the values normally and checking each variable individually to see if they are allocated would be a more "correct" way of doing this, but I don't want to exponentially bloat the script and I don't want people to have to copy the logic every time they want to add a new variable to the script and I can't just run the default_variables script before the config file allowing it to override the default values because some default values depend on config values.
Thanks in advance for any help!
Upvotes: 2
Views: 1238
Reputation: 75568
This is how I would do it:
# iterate on associative array indices (no need to do `echo ...`)
for default_var in "${!var[@]}"
do
# skip variables that have been previously declared (even if their value is null)
if [[ -z ${!default_var+.} ]]
then
# export each index name as a variable (the safer way with quotes)
export "$default_var=${var[$default_var]}"
fi
done
Upvotes: 1
Reputation: 46883
#!/bin/bash
# allows var to be used as an associative array
declare -A var
# variable declarations must be of the form:
# var[var_name]=var_value
# after processing loop, the above will be evaluated as:
# export var_name=var_value
# declare default variables
var[a]=a_val
var[b]=b_val
var[c]=c_val
var[d]=d_val
# iterate on associative array indices
for default_var in "${!var[@]}"; do #<=== no ugly `echo ...` needed
[[ "${!default_var}" ]] && continue #<=== indirect expansion
# export each index name as a variable
export "$default_var=${var[$default_var]}" #<=== use quotes!
done
echo "a=$a"
echo "b=$b"
echo "c=$c"
echo "d=$d"
I called this script banana
:
$ ./banana
a=a_val
b=b_val
c=c_val
d=d_val
$ a=gorilla ./banana
a=gorilla
b=b_val
c=c_val
d=d_val
Now this only checks if the variable is unset or empty, that is a user can't explicitly make a variable empty:
$ a= ./banana
a=a_val
b=b_val
c=c_val
d=d_val
To support this, you can instead do:
for default_var in "${!var[@]}"; do #<=== no ugly `echo ...` needed
if ! declare -p "$default_var" &>/dev/null; then
# export each index name as a variable
export "$default_var=${var[$default_var]}" #<=== use quotes!
fi
done
so that:
$ a= ./banana
a=
b=b_val
c=c_val
d=d_val
Upvotes: 2
Reputation: 241901
Don't use eval
, which causes its argument to be executed as a command. All you want is the value of the variable named by $default_var
. There is a perfectly good syntax for indirect variable reference:
if [[ -z ${!default_var} ]]
Although you really wanted to test for non-empty. -z
tests for empty. So it should be.
if [[ -n ${!default_var} ]]
Also, this is overcomplicated, and arguably incorrect:
for default_var in `echo "${!var[@]}"`
Just write:
for default_var in "${!var[@]}"
Upvotes: 2