简体   繁体   中英

How to set an array of environment variables in Bash

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?

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM