0

I am trying to implement a migration script to export some environment variables in bash.

It is more difficult to be explained that to implement.

Basically, there is a set of environment variables and a set of their default values.

A small fragment of the (gigantic) migration script is reported below:

REQUIRED_ENVIRONMENT_VARIABLES=( "BAR" "FOO" "BAZ" )
ENVIRONMENT_VARIABLES_DAFAULT_VALUES=( "/some/path" "0" "true" )

for i in "${!REQUIRED_ENVIRONMENT_VARIABLES[@]}"; do 
    echo "checking environment variable [$i] ${REQUIRED_ENVIRONMENT_VARIABLES[$i]} which default value is: [${ENVIRONMENT_VARIABLES_DAFAULT_VALUES[$i]}]"
    if [[ -z "${REQUIRED_ENVIRONMENT_VARIABLES[$i]}" ]]; then
      echo "variable ${REQUIRED_ENVIRONMENT_VARIABLES[$i]} exported with value ${ENVIRONMENT_VARIABLES_DAFAULT_VALUES[$i]}"
      echo "export ${REQUIRED_ENVIRONMENT_VARIABLES[$i]}"="${ENVIRONMENT_VARIABLES_DAFAULT_VALUES[$i]}" >> $HOME/.bash_profile
    fi
done

Simply, the for loop iterates for each variable into REQUIRED_ENVIRONMENT_VARIABLES:

  • if the var exists and has some value, skip it and continue to the next iteration;
  • if the var doesn't exist, create a new entry export VAR_NAME=DEFAULT_VALUE into the .bash_profile

So, for example, if the original contents of .bash_profile is:

(.bash_profile)

export FOO=1
export ASD=https://cool.url/
...

after running the migration script, the result should be:

(.bash_profile)

export FOO=1
export ASD=https://cool.url/
...
export BAR=/some/path
export BAZ=true

FOO remains untouched because already exists.

The problem with this code is that I see no new entries when I try to append it to the .bash_profile using the echo command. Why?

2 Answers 2

2

The problem is in the test

if [[ -z "${REQUIRED_ENVIRONMENT_VARIABLES[$i]}" ]]; then

This expands out an element of the array, and then checks to see if that array element was the null string (not whether it's the name of a variable). That is, on the first iteration when i=0, it expands to:

if [[ -z "BAR" ]]; then

...and since "BAR" is not the null string, the test fails. What you want is to treat BAR as a variable name, rather than a literal string. There are a couple of ways to do this. One is to use a negated -v test ("is there a variable by this name") (note that this is only available in newer versions of bash):

if [[ ! -v "${REQUIRED_ENVIRONMENT_VARIABLES[$i]}" ]]; then

Another option is to use bash's "indirect" variable expansion feature, by adding a ! at the beginning of the expansion:

if [[ -z "${!REQUIRED_ENVIRONMENT_VARIABLES[$i]}" ]]; then

Note that these aren't quite the same test; the first will treat a variable that's set to the null string as set, the second will not.

BTW, this is a near-duplicate of "How to check if a variable is set in Bash?", but since in this case the variable name is coming from an array, I considered it different enough to treat it as a separate question.

Sign up to request clarification or add additional context in comments.

Comments

1

Wouldn't it be easier to code it like this instead of using an array:

: ${BAR:=/some/path}
: ${FOO:=0}
: ${BAZ:=true}
: ${POOF:=$((FOO+25))}  # Default for variable depends on other variable
export FOO BAR BAZ POOF

In this source, the variables would be untouched if they are already set, but get a value if they are not.

2 Comments

Very cool! Are variables written in the .bash_profile by this way?
They are written in the way you write it. It's up to you. I use this style in those contexts, where I expect that a variable could already be set, but if it is not, I want to give it a value. In most cases, I use this in shell scripts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.